Сниппет запуска программы и получения результата (+ завершение всех процессов) [Дон шампиньон]

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Реакции
3 883
Баллы
113
Стандартный кубик для запуска программ (*.exe / *.bat / *.cmd файлов) не предоставляет возможности получить результат выполнения (т.е. если запускаемый *.bat файл выведет что-то на экран консоли, то это не возможно взять в качестве результата). Можно только получить EXIT CODE (код выхода программы), но это можно использовать только для проверки правильно ли выполнилась программа (если не ошибаюсь, то правильный код выхода - 0).

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

К тому же, бывает и такое, что одна утилита запускает другую, а та в свою очередь ещё несколько. Но из-за некорректного завершения программы - часть процессов не "убивается", а остается висеть дальше. Это со временем забивает память и винда начинает тормозить, пока не поймешь, что зависла куча процессов.

Чтобы избежать этого - я сделал небольшой сниппет и запаковал его в шаблон, который можно использовать как "проект в проекте". Для запуска: нужно прописать путь к нему и передать в переменных следующие значения:
  1. IN_program_path - путь к запускаемой программе.
  2. IN_program_arguments - аргументы для запуска программы (не обязательная переменная).
  3. IN_max_execution_seconds - время ожидания работы программы в секундах (сколько секунд ждать ответа).
  4. OUT_content - результат выполнения.
Использовать данный шаблон нужно следующим образом:
l90R1fQ.png



Также можно скопировать C#-кубик и к себе в проект, но обязательно нужно добавить ссылки из GAC + прописать Директивы Using + в общий скопировать метод CommonCode.KillProcessAndChildrens.

Шаблон во вложении :-)
 

Вложения

Последнее редактирование:
Обновленная версия шаблона!

Добавлено чтение русскоязычных символов с вывода из консоли (спасибо @DmitryAk)
 

Вложения

  • Спасибо
Реакции: seodima, orka13 и Nike59
Спасибо! Пользуюсь этим кодом для консольного запуска Grunt-заданий (форматирование css, html, пример - Grunt: Исключаем лишний CSS-код).
Но столкнулся с проблемой что командная строка запускается с папки зенки (\ZennoPoster Pro\Progs) как в этой теме. Путем экспериментов добился успеха. Просто вместо кода:
C#:
Развернуть Свернуть Копировать
StartInfo = new ProcessStartInfo {
        FileName = path,
        Arguments = arguments,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        CreateNoWindow = true
    }
Вставляем:
C#:
Развернуть Свернуть Копировать
StartInfo = new ProcessStartInfo {
        FileName = "grunt.cmd", // название файла для запуска
        WorkingDirectory = @"h:\grunt-uncss\node_modules\.bin\", // рабочая папка, в ней файл «grunt.cmd»
        Arguments = arguments,
        UseShellExecute = false,
        RedirectStandardOutput = true,
    RedirectStandardError = true,
        CreateNoWindow = true
    }
Ну или переменными пропишите пути\названия.
При этом папка Grunt, где лежат файлы для обработки - "h:\grunt-uncss\", сам конфигурационный файл - "h:\grunt-uncss\Gruntfile.js".

И если кто надумает повторить такое же, то выложу содержимое Gruntfile.js. В примере обрабатывался шаблон доргена PandoraBox, удалялись лишние стили из файла CSS (в папку h:\grunt-uncss\ закинуто все файлы шаблона, пути CSS в HTML-коде начинаются с "href='/" ):
Код:
Развернуть Свернуть Копировать
module.exports = function(grunt) {
    grunt.initConfig({
        uncss: {
        dist: {
            files: {
                'style_cleaned.css': ['template.html']
            }
        },
        options: {
            ignore: ['#id-to-ignore', '.auto-generated-class', '.ignore-this-class'],
            }
        }
    });
    grunt.loadNpmTasks('grunt-uncss');
    grunt.registerTask('default', 'uncss');
}
 
Последнее редактирование:
Grunt - это хорошо, а прикрученный к доргену - вдвойне хорошо) Не юзал их вместе, но идея на слух отличная)
 
Добрый день!

Подскажите, когда запускаю Ваш шаблон, то в переменной "OUT_content" оказывается результат запуска программы (bat файла), а не результат выполнения. Т.е. просто приветственное сообщение, но не результат работы, в моем случае - http://prntscr.com/jtpbuy . Так и должно быть, или я использую неправильный синтаксис в переменной "IN_program_arguments"?
 
Как подправить код, чтобы он и при ошибке записывал результат?
 
Как подправить код, чтобы он и при ошибке записывал результат?
Смотря о какой ошибке идет речь. Если программа выдает какую-то ошибку и это сообщение прилетает в лог, то вот так можно

Найти:
C#:
Развернуть Свернуть Копировать
throw new Exception(String.Format("Exception: {0}", errors));
Заменить на:
C#:
Развернуть Свернуть Копировать
project.Variables["OUT_content"].Value = errors;
throw new Exception(String.Format("Exception: {0}", errors));

Вроде должно помочь.
 
  • Спасибо
Реакции: Stelsgrower
Смотря о какой ошибке идет речь. Если программа выдает какую-то ошибку и это сообщение прилетает в лог, то вот так можно

Найти:
C#:
Развернуть Свернуть Копировать
throw new Exception(String.Format("Exception: {0}", errors));
Заменить на:
C#:
Развернуть Свернуть Копировать
project.Variables["OUT_content"].Value = errors;
throw new Exception(String.Format("Exception: {0}", errors));

Вроде должно помочь.
Спасибо! Помогло!
 
Смотря о какой ошибке идет речь. Если программа выдает какую-то ошибку и это сообщение прилетает в лог, то вот так можно

Найти:
C#:
Развернуть Свернуть Копировать
throw new Exception(String.Format("Exception: {0}", errors));
Заменить на:
C#:
Развернуть Свернуть Копировать
project.Variables["OUT_content"].Value = errors;
throw new Exception(String.Format("Exception: {0}", errors));

Вроде должно помочь.
Можете еще помочь разобраться в общем коде вашего проекта?

Код:
Развернуть Свернуть Копировать
            ManagementObjectSearcher processSearcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
                       ManagementObjectCollection processCollection = processSearcher.Get();
Мне нужны PID всех дочерних процессов основного, знаю, что их можно получить этими двумя строками из Вашего шаблона. Как processCollection положить в список а затем при обращении из кубика C# положить этот список PID-ов в переменную?
 
Мне нужны PID всех дочерних процессов основного, знаю, что их можно получить этими двумя строками из Вашего шаблона. Как processCollection положить в список а затем при обращении из кубика C# положить этот список PID-ов в переменную?
В общем коде перед:
C#:
Развернуть Свернуть Копировать
public static void KillProcessAndChildrens(int pid)
Добавляем:
C#:
Развернуть Свернуть Копировать
        public static string GetChildrenProcessList(int pid) {
            List<string> childrens = new List<string>();
         
            ManagementObjectSearcher processSearcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
            ManagementObjectCollection processCollection = processSearcher.Get();

            if (processCollection != null) {
                foreach (ManagementObject mo in processCollection) {
                    childrens.Add(Convert.ToString(mo["ProcessID"]));
                }
            }
         
            return String.Join(",", childrens);
        }

Затем из кубика C# вызываем:
C#:
Развернуть Свернуть Копировать
string childs = CommonCode.GetChildrenProcessList(2684); // 2684 - Process ID, не строка(!), число(!)
project.SendInfoToLog(childs); // вывести в лог
return childs; // вернуть pid дочерних процессов или пустую строку, если их нет
 
  • Спасибо
Реакции: Stelsgrower и orka13
В общем коде перед:
C#:
Развернуть Свернуть Копировать
public static void KillProcessAndChildrens(int pid)
Добавляем:
C#:
Развернуть Свернуть Копировать
        public static string GetChildrenProcessList(int pid) {
            List<string> childrens = new List<string>();
        
            ManagementObjectSearcher processSearcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
            ManagementObjectCollection processCollection = processSearcher.Get();

            if (processCollection != null) {
                foreach (ManagementObject mo in processCollection) {
                    childrens.Add(Convert.ToString(mo["ProcessID"]));
                }
            }
        
            return String.Join(",", childrens);
        }

Затем из кубика C# вызываем:
C#:
Развернуть Свернуть Копировать
string childs = CommonCode.GetChildrenProcessList(2684); // 2684 - Process ID, не строка(!), число(!)
project.SendInfoToLog(childs); // вывести в лог
return childs; // вернуть pid дочерних процессов или пустую строку, если их нет
Спасибо за развернутый ответ! Вдохновляете меня своими шаблонами и кодами, побольше бы таких как, Вы на форуме
 
Спасибо большое за код, оказался очень полезным.
 
@Lord_Alfred
Привет.
После успешного выполнения OUT_content остается пустым
Пробовал запускать Putty и Imagemajick (montage.exe - объединял картинки, но возможно в данном случае консоль и не содержит никакой информации)
Однако Putty вот что отдает если запускать через кубик Zenno и показывать окно выполнения:

upload_2019-8-11_14-8-29.png

Почему эта информация не уходит в OUT_content?
 

Вложения

  • upload_2019-8-11_14-8-27.png
    upload_2019-8-11_14-8-27.png
    11,6 KB · Просмотры: 5
Последнее редактирование:
Почему эта информация не уходит в OUT_content?
Она может уходить в STD ERR. Проверь наверняка в стандартном новом кубике куда она идет.
Ну а вообще, судя по тому что сделали кубик новый - этот шаблон более и не нужен ведь :)
 
  • Спасибо
Реакции: udder
Она может уходить в STD ERR. Проверь наверняка в стандартном новом кубике куда она идет.
Ну а вообще, судя по тому что сделали кубик новый - этот шаблон более и не нужен ведь :-)

Я понял, да в настройках кубика теперь есть вывод, на момент написания вашего C# дополнения данных фич не было, но все ровно у меня в переменные пустота уходит, я думал будет информация которую я вижу в консоли. Как на скрине выше что я прикладывал.. Но я вышел из ситуации включив в Putty запись логов и затем уже лог файл распрашиваю
upload_2019-8-11_17-32-7.png
 
  • Спасибо
Реакции: Lord_Alfred
В общем коде перед:
C#:
Развернуть Свернуть Копировать
public static void KillProcessAndChildrens(int pid)
Добавляем:
C#:
Развернуть Свернуть Копировать
        public static string GetChildrenProcessList(int pid) {
            List<string> childrens = new List<string>();
        
            ManagementObjectSearcher processSearcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
            ManagementObjectCollection processCollection = processSearcher.Get();

            if (processCollection != null) {
                foreach (ManagementObject mo in processCollection) {
                    childrens.Add(Convert.ToString(mo["ProcessID"]));
                }
            }
        
            return String.Join(",", childrens);
        }

Затем из кубика C# вызываем:
C#:
Развернуть Свернуть Копировать
string childs = CommonCode.GetChildrenProcessList(2684); // 2684 - Process ID, не строка(!), число(!)
project.SendInfoToLog(childs); // вывести в лог
return childs; // вернуть pid дочерних процессов или пустую строку, если их нет
А можно как-то сделать, чтобы окно запущенного процесса не скрывалось? т.е чтобы его было видно?
 
Теперь ясно. Есть смысл пользоваться? Или держать в параллели?
 
Теперь ясно. Есть смысл пользоваться? Или держать в параллели?
Я только на 7й версии сижу. Привык уже и не хочу обратно) Тут каждый сам решает.

PS: по поводу отсутствия этих кнопок в 5ке я не знаю должны ли они быть там, посмотри по changelog - может это баг и они должны быть
 
  • Спасибо
Реакции: bizzon
Можно как-то в ходе работы программы(bat) вводить туда какие-то данные?
 
Спасибо! Пользуюсь этим кодом для консольного запуска Grunt-заданий (форматирование css, html, пример - Grunt: Исключаем лишний CSS-код).
Но столкнулся с проблемой что командная строка запускается с папки зенки (\ZennoPoster Pro\Progs) как в этой теме. Путем экспериментов добился успеха. Просто вместо кода:
C#:
Развернуть Свернуть Копировать
StartInfo = new ProcessStartInfo {
        FileName = path,
        Arguments = arguments,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        CreateNoWindow = true
    }
Вставляем:
C#:
Развернуть Свернуть Копировать
StartInfo = new ProcessStartInfo {
        FileName = "grunt.cmd", // название файла для запуска
        WorkingDirectory = @"h:\grunt-uncss\node_modules\.bin\", // рабочая папка, в ней файл «grunt.cmd»
        Arguments = arguments,
        UseShellExecute = false,
        RedirectStandardOutput = true,
    RedirectStandardError = true,
        CreateNoWindow = true
    }
Ну или переменными пропишите пути\названия.
При этом папка Grunt, где лежат файлы для обработки - "h:\grunt-uncss\", сам конфигурационный файл - "h:\grunt-uncss\Gruntfile.js".

И если кто надумает повторить такое же, то выложу содержимое Gruntfile.js. В примере обрабатывался шаблон доргена PandoraBox, удалялись лишние стили из файла CSS (в папку h:\grunt-uncss\ закинуто все файлы шаблона, пути CSS в HTML-коде начинаются с "href='/" ):
Код:
Развернуть Свернуть Копировать
module.exports = function(grunt) {
    grunt.initConfig({
        uncss: {
        dist: {
            files: {
                'style_cleaned.css': ['template.html']
            }
        },
        options: {
            ignore: ['#id-to-ignore', '.auto-generated-class', '.ignore-this-class'],
            }
        }
    });
    grunt.loadNpmTasks('grunt-uncss');
    grunt.registerTask('default', 'uncss');
}
Реально ли как то получить WM_COPYDATA сообщение от исполняемого процесса в zennoposter?
 
Было ли у кого-то такое, что ответ из cmd слишком длинный и потому не записывается в переменную STD_OUT? В какую сторону копать? Более короткий ответ выводится, эти же данные в обычной cmd так же нормально выводятся, только в зенке беда.
 

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)