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

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

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

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

Почему стандартный метод КомандаСистемы() не подходит?

Встроенная функция КомандаСистемы() разработана для простого линейного вызова команд операционной системы. При ее вызове платформа 1С напрямую обращается к интерпретатору командной строки Windows, при этом окно консоли создается в стандартном видимом режиме. Изменить этот режим средствами самого метода невозможно — у него просто отсутствуют соответствующие параметры для управления отображением окон.

Попытки прописать в исполняемом .bat файле команду @echo off лишь скрывают вывод самих команд внутри консоли, но само черное окно программы при этом все равно появляется на экране. Для полноценного скрытия нам придется прибегнуть к возможностям операционной системы, а именно к технологиям автоматизации Windows Script Host (WSH) или инструментарию управления WMI.

Решение №1: Основной способ через WScript.Shell и метод Run

Наиболее надежным, проверенным временем и простым способом запуска команд в скрытом режиме является использование системного COM-объекта WScript.Shell. Этот объект предоставляет мощный метод Run, который позволяет тонко настраивать визуальный режим запускаемого процесса.

Рассмотрим синтаксис метода Run:

Объект.Run(Команда, РежимОкна, ОжидатьЗавершения)

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

  1. Команда (строка) — исполняемый файл или консольная команда, которую необходимо выполнить. Если путь содержит пробелы, его нужно обязательно брать в дополнительные кавычки.
  2. РежимОкна (число) — параметр, управляющий внешним видом окна запускаемого процесса. Здесь кроется секрет нашего решения:
    • 0 — скрывает окно полностью. Программа запускается в фоновом режиме, пользователь ничего не видит на экране.
    • 1 — стандартный режим отображения активного окна.
    • 2 — запускает программу в свернутом виде (окно сворачивается на панель задач).
    • 7 — запускает в свернутом виде без изменения активного окна пользователя (фокус остается в 1С).
  3. ОжидатьЗавершения (булево / число) — параметр, определяющий синхронность выполнения:
    • 1 (или Истина) — 1С приостановит выполнение текущего кода и будет дожидаться, пока запущенная внешняя программа завершит свою работу. Метод вернет код завершения процесса (обычно 0 означает успех).
    • 0 (или Ложь) — асинхронный запуск. Команда отправляется на выполнение, и 1С мгновенно продолжает работу своего кода, не дожидаясь окончания внешнего процесса.

Теперь посмотрим на практический пример реализации для платформы 1С:Предприятие 7.7:


// Пример скрытого выполнения команды в 1С 7.7
Процедура ВыполнитьСкрыто()
    Шелл = СоздатьОбъект("WScript.Shell");
    // Устанавливаем рабочий каталог, если это необходимо
    ФС.УстТекКаталог("C:\Temp\");
    
    // Запускаем пинг скрыто (0), дожидаемся завершения (1)
    Результат = Шелл.Run("cmd /c ping 192.168.2.1 > 1.txt", 0, 1);
    
    Если Результат = 0 Тогда
        Сообщить("Команда выполнена успешно!");
    Иначе
        Сообщить("При выполнении команды возникла ошибка с кодом: " + Результат);
    КонецЕсли;
КонецПроцедуры

Аналогичный код для современных версий платформы 1С:Предприятие 8.х (Обычные или Управляемые формы) выглядит следующим образом:


// Пример скрытого выполнения команды в 1С 8.х
Процедура ВыполнитьСкрытоНа8()
    Шелл = Новый COMОбъект("WScript.Shell");
    Команда = "cmd /c ping 192.168.2.1 > C:\Temp\1.txt";
    
    // Запуск в скрытом режиме с ожиданием завершения
    КодВозврата = Шелл.Run(Команда, 0, Истина);
    
    Если КодВозврата = 0 Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Пинг завершен успешно!");
    Иначе
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка выполнения! Код возврата: " + КодВозврата);
    КонецЕсли;
КонецПроцедуры

Важный нюанс: Использование cmd /c и перенаправление вывода

Проанализируем ситуацию, описанную в сообщениях форума. Автор темы столкнулся с тем, что простая команда ping 192.168.2.1 > 1.txt не создавала файл и возвращала ошибку при попытке скрытого запуска. Почему это происходит?

Дело в том, что символ перенаправления потока вывода > (а также конвейеры |) не являются свойствами исполняемого файла ping.exe. Они являются внутренними операторами командного интерпретатора Windows (cmd.exe). Когда мы вызываем команду напрямую через метод Run, операционная система пытается найти исполняемый файл с именем "ping" и передать ему все остальные символы как параметры. Файл ping.exe ничего не знает про оператор > 1.txt и воспринимает это как ошибку синтаксиса.

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

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

"cmd /c ping 192.168.2.1 > C:\123\1.txt"

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


КомандаСПробелами = "cmd /c ""C:\Program Files\My App\app.exe"" ""C:\My Documents\file.txt""";

Решение №2: Чтение вывода программы напрямую через метод Exec (без создания временных файлов)

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

Мы можем избежать создания временных файлов на диске, если воспользуемся методом Exec вместо Run. Метод Exec запускает приложение в отдельном процессе и предоставляет прямой доступ к потокам ввода-вывода StdIn, StdOut и StdErr через оперативную память.

Выясним, как прочитать результат работы утилиты напрямую в 1С:


// Пример использования Exec для получения вывода в 1С
Шелл = Новый COMОбъект("WScript.Shell");
// Запускаем процесс
Процесс = Шелл.Exec("ping 192.168.2.1");

// Считываем весь поток стандартного вывода в переменную
РезультатТекст = Процесс.StdOut.ReadAll();

// Выводим результат в окно сообщений 1С
Сообщить(РезультатТекст);

Важные особенности использования метода Exec:

  1. При вызове метода Exec консольное окно может кратковременно мелькнуть на долю секунды на экране пользователя. Скрыть его на 100% так же надежно, как методом Run с параметром 0, к сожалению, невозможно.
  2. Опасность зависания программы (Deadlock): Внутренние буферы вывода Windows имеют ограниченный объем (обычно около 4 КБ). Если вызываемая вами утилита генерирует большой объем текста (например, длинный лог выполнения), а вы не считываете его в реальном времени, буфер переполнится, и процесс зависнет навсегда. Чтобы этого избежать при работе со сложными утилитами, перенаправляйте поток ошибок в поток стандартного вывода, добавляя конструкцию 2>&1 в конец строки команды.

Решение №3: Запуск абсолютно скрытых процессов через WMI (Win32_Process)

Если вам требуется гарантированно фоновый запуск процесса без малейших визуальных проявлений и без использования объекта WScript.Shell, существует альтернативный способ с использованием инструментария WMI (Windows Management Instrumentation). Метод Create системного класса Win32_Process позволяет создавать системные процессы в полностью изолированном фоновом режиме.

Рассмотрим пример реализации этого подхода на платформе 1С:


// Использование WMI для скрытого запуска
Локатор = СоздатьОбъект("WbemScripting.SWbemLocator");
// Подключаемся к локальному серверу WMI
Сервис = Локатор.ConnectServer(".");
// Получаем доступ к классу управления процессами
УправлениеПроцессами = Сервис.Get("Win32_Process");

ИдентификаторПроцесса = 0;
// Метод Create принимает параметры: Команда, РабочийКаталог, КонфигурацияЗапуска, ИДСозданногоПроцесса
РезультатКод = УправлениеПроцессами.Create("ping 192.168.2.1", "C:\Temp\", , ИдентификаторПроцесса);

Если РезультатКод = 0 Тогда
    Сообщить("Процесс успешно запущен в фоне с PID: " + ИдентификаторПроцесса);
Иначе
    Сообщить("Не удалось запустить фоновый процесс. Код ошибки WMI: " + РезультатКод);
КонецЕсли;

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

Рекомендации для современной платформы 1С:Предприятие 8.3

Если вы разрабатываете решение на актуальной версии платформы 1С 8.3, рекомендуется уходить от старых методов вроде КомандаСистемы() и использовать современные встроенные средства:

  1. Метод ЗапуститьПриложение(): Этот метод является встроенным аналогом WScript.Shell.Run. Он поддерживает параметры ожидания завершения, скрытия окна (через параметры запуска ассоциированного приложения) и получения кода возврата. Использование встроенных методов делает ваш код более кроссплатформенным (актуально при работе серверов 1С на операционных системах семейства Linux).
  2. Использование PowerShell: Вместо устаревшего командного процессора cmd.exe в современных ОС Windows гораздо эффективнее вызывать PowerShell. У него есть встроенный параметр для полного скрытия окна. Вы можете вызывать его следующим образом:

    powershell -WindowStyle Hidden -Command "ВашаКоманда"

    Это избавляет от необходимости писать сложные обертки на VBScript или использовать сторонние компоненты напрямую.

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

← На главную