Как запустить консольное приложение в фоновом режиме из 1С и решить проблему зависания интерфейса

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

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

Способ 1. Использование встроенного метода платформы ЗапуститьПриложение

Начнем с анализа штатных инструментов платформы 1С:Предприятие 8. Рассмотрим синтаксис функции ЗапуститьПриложение(). Данный метод выполняет запуск внешнего приложения напрямую, минуя командный интерпретатор Windows (в отличие от устаревшего метода КомандаСистемы(), который всегда открывает окно консоли).

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

Рассмотрим пример асинхронного запуска внешней программы:


// Запуск приложения без ожидания его закрытия
ПутьКПрограмме = "C:\Program Files\MyUtility\utility.exe";
ПараметрыЗапуска = "--silent --import data.xml";
СтрокаЗапуска = """" + ПутьКПрограмме + """ " + ПараметрыЗапуска;

ЗапуститьПриложение(СтрокаЗапуска, , Ложь);

Важный нюанс: если запуск происходит непосредственно на клиенте (в тонком или толстом клиенте), операционная система все равно может отобразить окно запускаемой программы (если это графическое приложение или консольный скрипт, явно требующий консоли). Чтобы полностью исключить отображение окон у пользователя, запуск можно перенести на сторону сервера. На сервере 1С все процессы выполняются в изолированной неинтерактивной сессии Windows или Linux, поэтому пользователь физически не сможет увидеть всплывающие окна.

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


&НаКлиенте
Процедура ЗапуститьФоновоеПриложениеАсинхронно()
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗапускаПриложения", ЭтотОбъект);
    НачатьЗапускПриложения(ОписаниеОповещения, "C:\Windows\System32\notepad.exe");
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗапускаПриложения(КодВозврата, ДополнительныеПараметры) Экспорт
    // Данный код выполнится после запуска или закрытия приложения (в зависимости от настроек)
    Сообщить("Процесс запуска инициирован успешно.");
КонецПроцедуры

Способ 2. Скрытый запуск через COM-объект WScript.Shell (Windows Script Host)

Если вам необходимо гарантированно скрыть окно консоли при запуске на стороне Windows-клиента, стандартных возможностей ЗапуститьПриложение может не хватить. В этом случае на помощь приходит объект автоматизации операционной системы — WScript.Shell.

Этот объект предоставляет метод Run(), который позволяет очень гибко настраивать стиль отображения окна запускаемой программы. Синтаксис метода выглядит следующим образом:

Run(Command, [WindowStyle], [WaitOnReturn])

Наибольший интерес для нас представляет параметр WindowStyle. Передав в него значение 0, мы указываем операционной системе, что окно запускаемого процесса должно быть полностью скрыто (режим Hide), а фокус ввода должен остаться у вызывающей программы (то есть у 1С).

Разберем практический пример реализации этого метода в коде 1С:


Процедура ЗапуститьКонсольСкрыто(ПутьКФайлу, ПараметрыКоманды) Экспорт
    Попытка
        // Создаем COM-объект для работы с оболочкой Windows
        WshShell = Новый COMОбъект("Wscript.Shell");
        
        // Формируем полную строку запуска с учетом кавычек для путей с пробелами
        ПолнаяКоманда = """" + ПутьКФайлу + """ " + ПараметрыКоманды;
        
        // Первый параметр - команда запуска
        // Второй параметр (0) - полностью скрывает окно запускаемого приложения
        // Третий параметр (Ложь) - не ожидать завершения работы приложения (асинхронно)
        WshShell.Run(ПолнаяКоманда, 0, Ложь);
        
    Исключение
        ВызватьИсключение "Не удалось запустить приложение в фоновом режиме. Ошибка: " + ОписаниеОшибки();
    КонецПопытки;
КонецПроцедуры

Этот способ идеально подходит для скрытого запуска системных утилит (например, архиватора 7-Zip для фоновой распаковки, консольных конвертеров изображений или утилиты curl/wget для передачи файлов), не отвлекая пользователя мерцанием консольных окон.

Способ 3. Использование PowerShell для скрытого запуска

В современных ИТ-инфраструктурах использование классического WScript.Shell может блокироваться внутренними политиками безопасности Active Directory или строгими правилами антивирусного ПО. В качестве современной альтернативы на рабочих станциях под управлением Windows можно использовать PowerShell. Он позволяет запускать фоновые процессы с параметром скрытия окна.

Посмотрим на пример вызова скрытого процесса через PowerShell из 1С:


Процедура ЗапуститьЧерезPowerShellСкрыто(ПутьКПриложению, Аргументы)
    КомандаPS = "Start-Process '" + ПутьКПриложению + "' -ArgumentList '" + Аргументы + "' -WindowStyle Hidden";
    СтрокаЗапуска = "powershell -NoProfile -NonInteractive -WindowStyle Hidden -Command """ + КомандаPS + """";
    
    ЗапуститьПриложение(СтрокаЗапуска, , Ложь);
КонецПроцедуры

Параметр -WindowStyle Hidden указывает интерпретатору PowerShell запустить целевой дочерний процесс в полностью скрытом режиме, предотвращая его появление на панели задач и рабочем столе.

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

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

Если решать эту задачу через вызов внешнего плеера (например, VLC Media Player) с помощью ЗапуститьПриложение, то возникают две проблемы:

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

Для элегантного решения этой проблемы без стороннего софта мы можем использовать встроенные мультимедийные COM-компоненты Windows. Самым стабильным и функциональным решением является использование библиотеки проигрывателя Windows Media Player (WMPlayer.OCX).

Давайте проанализируем готовый код, который позволяет воспроизводить аудиофайлы в параллельном режиме без создания видимых окон и без зависания интерфейса 1С:


Процедура ВоспроизвестиЗвуковойФайл(ИмяФайла) Экспорт
    УспешноВоспроизведено = Ложь;
    
    // Попытка 1: Использование современного COM-объекта Windows Media Player
    Попытка
        COMОбъект = Новый COMОбъект("WMPlayer.OCX");
        COMОбъект.URL = ИмяФайла;
        COMОбъект.controls.Play();
        УспешноВоспроизведено = Истина;
    Исключение
        // Ошибка создания объекта или чтения файла, переходим к альтернативам
    КонецПопытки;
    
    // Попытка 2: Использование устаревшего, но совместимого интерфейса MediaPlayer
    Если Не УспешноВоспроизведено Тогда
        Попытка
            COMОбъект = Новый COMОбъект("MediaPlayer.MediaPlayer");
            COMОбъект.Open(ИмяФайла);
            COMОбъект.Play();
            УспешноВоспроизведено = Истина;
        Исключение
            // Альтернативный объект также недоступен
        КонецПопытки;
    КонецЕсли;
    
    // Попытка 3: Экстренный скрытый запуск классического плеера через WScript.Shell
    Если Не УспешноВоспроизведено Тогда
        Попытка
            COMОбъект = Новый COMОбъект("WScript.Shell");
            // Запуск системного wmplayer с параметром скрытия окна 0
            COMОбъект.Run("wmplayer """ + ИмяФайла + """", 0, Ложь);
            УспешноВоспроизведено = Истина;
        Исключение
            ЗаписьЖурналаРегистрации("Мультимедиа", УровеньЖурналаРегистрации.Предупреждение, , , 
                "Не удалось воспроизвести файл: " + ИмяФайла + ". Ошибка: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

Почему этот подход работает идеально в нашей ситуации?

Кроссплатформенная альтернатива: Воспроизведение звука через HTML5

Описанные выше методы с COM-объектами отлично работают в операционных системах семейства Windows, однако они не будут работать в веб-клиенте 1С, а также на рабочих станциях под управлением Linux или macOS. Если ваша конфигурация используется на различных платформах, лучшим решением будет использование стандартного элемента формы — Поля HTML-документа.

Современные браузеры и встроенные контейнеры 1С поддерживают стандарт HTML5, в котором есть тег <audio>. Мы можем динамически загружать и воспроизводить аудиофайлы с помощью JavaScript. Это решение работает асинхронно, кроссплатформенно и не требует никаких внешних прав или регистрации библиотек в ОС.

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

При создании формы инициализируем пустое HTML-поле базовой структурой:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Формируем базовый HTML с поддержкой JS-функции проигрывания
    ТекстHTML = 
    "<html>
    |<head>
    |   <script>
    |       function playSound(audioPath) {
    |           var audio = new Audio(audioPath);
    |           audio.play();
    |       }
    |   </script>
    |</head>
    |<body></body>
    |</html>";
    
    ПлеерHTML = ТекстHTML;
КонецПроцедуры

Теперь для воспроизведения звукового файла нам достаточно вызвать JavaScript-функцию playSound из кода 1С, передав ей путь к файлу (это может быть локальный путь или даже URL-ссылка на веб-сервер):


&НаКлиенте
Процедура ПроигратьЗвукКроссплатформенно(ПутьКФайлу)
    // Преобразуем локальный путь для корректного чтения браузером (заменяем слеши)
    ПодготовленныйПуть = СтрЗаменить(ПутьКФайлу, "\", "/");
    
    // Если путь локальный, добавим протокол file://
    Если Не Найти(ПодготовленныйПуть, "http://") = 1 И Не Найти(ПодготовленныйПуть, "https://") = 1 Тогда
        ПодготовленныйПуть = "file:///" + ПодготовленныйПуть;
    КонецЕсли;

    // Вызываем JS функцию на веб-странице
    Элементы.ПлеерHTML.Документ.defaultView.playSound(ПодготовленныйПуть);
КонецПроцедуры

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

← На главную