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

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
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 - результат выполнения.
Использовать данный шаблон нужно следующим образом:



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

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

Вложения

Последнее редактирование:

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Обновленная версия шаблона!

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

Вложения

  • Спасибо
Реакции: seodima, orka13 и Nike59

orka13

Client
Регистрация
07.05.2015
Сообщения
2 177
Благодарностей
2 184
Баллы
113
Спасибо! Пользуюсь этим кодом для консольного запуска 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');
}
 
Последнее редактирование:

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Grunt - это хорошо, а прикрученный к доргену - вдвойне хорошо) Не юзал их вместе, но идея на слух отличная)
 

Aplabs

Новичок
Регистрация
11.06.2018
Сообщения
12
Благодарностей
1
Баллы
3
Добрый день!

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

Stelsgrower

Client
Регистрация
21.12.2018
Сообщения
134
Благодарностей
63
Баллы
28
Как подправить код, чтобы он и при ошибке записывал результат?
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Как подправить код, чтобы он и при ошибке записывал результат?
Смотря о какой ошибке идет речь. Если программа выдает какую-то ошибку и это сообщение прилетает в лог, то вот так можно

Найти:
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

Stelsgrower

Client
Регистрация
21.12.2018
Сообщения
134
Благодарностей
63
Баллы
28
Смотря о какой ошибке идет речь. Если программа выдает какую-то ошибку и это сообщение прилетает в лог, то вот так можно

Найти:
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

Client
Регистрация
21.12.2018
Сообщения
134
Благодарностей
63
Баллы
28
Смотря о какой ошибке идет речь. Если программа выдает какую-то ошибку и это сообщение прилетает в лог, то вот так можно

Найти:
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-ов в переменную?
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Мне нужны 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

Stelsgrower

Client
Регистрация
21.12.2018
Сообщения
134
Благодарностей
63
Баллы
28
В общем коде перед:
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 дочерних процессов или пустую строку, если их нет
Спасибо за развернутый ответ! Вдохновляете меня своими шаблонами и кодами, побольше бы таких как, Вы на форуме
 

Zheka84

Client
Регистрация
13.10.2018
Сообщения
163
Благодарностей
24
Баллы
18
Спасибо большое за код, оказался очень полезным.
 

udder

Client
Регистрация
28.03.2017
Сообщения
618
Благодарностей
128
Баллы
43
@Lord_Alfred
Привет.
После успешного выполнения OUT_content остается пустым
Пробовал запускать Putty и Imagemajick (montage.exe - объединял картинки, но возможно в данном случае консоль и не содержит никакой информации)
Однако Putty вот что отдает если запускать через кубик Zenno и показывать окно выполнения:

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

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

Вложения

Последнее редактирование:

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Почему эта информация не уходит в OUT_content?
Она может уходить в STD ERR. Проверь наверняка в стандартном новом кубике куда она идет.
Ну а вообще, судя по тому что сделали кубик новый - этот шаблон более и не нужен ведь :-)
 
  • Спасибо
Реакции: udder

udder

Client
Регистрация
28.03.2017
Сообщения
618
Благодарностей
128
Баллы
43
Она может уходить в STD ERR. Проверь наверняка в стандартном новом кубике куда она идет.
Ну а вообще, судя по тому что сделали кубик новый - этот шаблон более и не нужен ведь :-)
Я понял, да в настройках кубика теперь есть вывод, на момент написания вашего C# дополнения данных фич не было, но все ровно у меня в переменные пустота уходит, я думал будет информация которую я вижу в консоли. Как на скрине выше что я прикладывал.. Но я вышел из ситуации включив в Putty запись логов и затем уже лог файл распрашиваю
upload_2019-8-11_17-32-7.png
 
  • Спасибо
Реакции: Lord_Alfred

Stelsgrower

Client
Регистрация
21.12.2018
Сообщения
134
Благодарностей
63
Баллы
28
В общем коде перед:
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 дочерних процессов или пустую строку, если их нет
А можно как-то сделать, чтобы окно запущенного процесса не скрывалось? т.е чтобы его было видно?
 

bizzon

Client
Регистрация
08.09.2015
Сообщения
1 103
Благодарностей
132
Баллы
63

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Та же версия, но 7ая ветка:

49540
 

bizzon

Client
Регистрация
08.09.2015
Сообщения
1 103
Благодарностей
132
Баллы
63
Теперь ясно. Есть смысл пользоваться? Или держать в параллели?
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
Теперь ясно. Есть смысл пользоваться? Или держать в параллели?
Я только на 7й версии сижу. Привык уже и не хочу обратно) Тут каждый сам решает.

PS: по поводу отсутствия этих кнопок в 5ке я не знаю должны ли они быть там, посмотри по changelog - может это баг и они должны быть
 
  • Спасибо
Реакции: bizzon

Shytov

Client
Регистрация
11.09.2018
Сообщения
175
Благодарностей
39
Баллы
28

Shytov

Client
Регистрация
11.09.2018
Сообщения
175
Благодарностей
39
Баллы
28
Можно как-то в ходе работы программы(bat) вводить туда какие-то данные?
 

Stelsgrower

Client
Регистрация
21.12.2018
Сообщения
134
Благодарностей
63
Баллы
28
Спасибо! Пользуюсь этим кодом для консольного запуска 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?
 

Asmus003

Client
Регистрация
25.03.2018
Сообщения
259
Благодарностей
66
Баллы
28
Было ли у кого-то такое, что ответ из cmd слишком длинный и потому не записывается в переменную STD_OUT? В какую сторону копать? Более короткий ответ выводится, эти же данные в обычной cmd так же нормально выводятся, только в зенке беда.
 

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