Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.149.252.37] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Необходимо из написанной мной программы запустить другое приложение с 2мя атрибутами, аналогично команде:
start "" "C:\convecter_db_to_xml.exe" "C:\Users\Desktop\bdrelese" "7" Как это можно выполнить? |
Сообщ.
#2
,
|
|
|
В районе этого:
#include <stdio.h> #include <process.h> int main( int /*argc*/, char */*argv*/[] ) { _spawnl( _P_WAIT, "C:\\convecter_db_to_xml.exe", "C:\\Users\\Desktop\\bdrelese", "7", NULL); return(0); } |
Сообщ.
#3
,
|
|
|
Выбирай - ShellExecute,CreateProcess,spawnl,spawnlp.....
|
Сообщ.
#4
,
|
|
|
ShellExecute(Handle, NULL, (BdDir+"\\convecter_db_to_xml.exe").c_str(), "'C:\\Users\\Desktop\\bdrelese' '7'", NULL, SW_RESTORE);
Я правильно атрибуты указал? |
Сообщ.
#5
,
|
|
|
Цитата Bas @ Выбирай - ShellExecute,CreateProcess,spawnl,spawnlp..... Ребята, несколько расширю вопрос. 1. Управляющей программой, написанной в C++ Builder, циклически запускается на счет тяжелая программа. 2. На каждом шаге цикла тяжелая программа запускается с уникальными начальными данными, заданными в файле настроек. Этот файл настроек выступает в качестве параметра тяжелой программы в командной строке. 3. После выполнения тяжелой программы управляющая программа сохраняет в создаваемых ею уникальных каталогах результаты работы тяжелой программы. 4. Примечание: тяжелая программа на то и тяжелая, что работает она примерно 5 минут даже на относительно мощных машинах. Сейчас управляющая программа запускает тяжелую программу с параметром-файлом функцией spawnl(P_WAIT, ... Не нравится то, что во время исполнения тяжелой программы управляющая программа примерно 5 минут недоступна! Выглядит, как зависшая! Вопрос: как сделать так, чтобы управляющая программа не теряла связи с операционной системой и в то же время не теряла контроль над тяжелой программой? Например, хочется во время работы тяжелой программы отметить в управляющей программе чекбокс "Прервать цикл выполнения тяжелой программы". Пока это все делаем так: 1. Через ctrl+alt+del снимаем со счета управляющую программу. 2. А потом останавливаем штатным образом тяжелую программу (она имеет графический интерфейс!) |
Сообщ.
#6
,
|
|
|
mkudritsky, запускай в отдельном потоке. А поток GUI оставь для управления.
|
Сообщ.
#7
,
|
|
|
JoeUser, спасибо за помощь!
Но я новичок в C++ и пока плохо ориентируюсь. А как технически запустить тяжелую дочернюю программу в отдельном потоке? Какими командами? Я пока прорабатывал такой вариант: spawnl(P_NOWAIT, ...); ... wait(NULL); Тут можно между командами spawnl и wait (cwait) выполнить какие-либо операторы. Но управляющая программа, дойдя до оператора wait, опять "зависает" до завершения тяжелой программы. А отследить факт того, что дочерняя тяжелая программа выполнена, можно, как я понял, только оператором wait (cwait). |
Сообщ.
#8
,
|
|
|
Наверное, это немного сложнее будет.
Если запускать программу через функцию BOOL ShellExecuteEx(LPSHELLEXECUTEINFO lpExecInfo); DWORD PID = GetProcessID(ExeInfo.hProcess) Т.е. в идеале программа сможет продолжать работу, но иметь возможность контролировать запущенный процесс. Но с этим механизмом придется немного повозиться: MSDN ShellExecuteEx function MSDN SHELLEXECUTEINFO structure MSDN GetProcessId function |
Сообщ.
#9
,
|
|
|
Цитата mkudritsky @ А отследить факт того, что дочерняя тяжелая программа выполнена, можно, как я понял, только оператором wait (cwait). Если использовать для запуска функции ShellExecute или CreateProcess, возвращающие хэндл запущенного процесса (hProcess), то можно контролировать его завершение несколькими способами. Самый простой - запустить таймер, в функции которого проверять завершение процесса по GetExitCodeProcess(hProcess,&ExitCode) && (ExitCode != STILL_ACTIVE). Другой способ - использовать циклический вызов функции ожидания MsgWaitForMultipleObjects с pHandles = &hProcess и dwWakeMask = QS_ALLINPUT. Если функция возвращает WAIT_OBJECT_0 (= 0), то ожидаемый процесс завершен - выходим из цикла. Если возвращаемое значение = WAIT_OBJECT_0+1 (= 1), то пришло сообщение - вызываем Application->ProcessMessages и крутим цикл дальше. Добавлено Цитата simsergey @ Посмотрите, возможно по завершении процесса, который Вы запустили, функция GetProcessID будет возвращать ноль. (а не его PID). Не будет. Информация о процессе сохраняется до тех пор, пока не будут закрыты все его хэндлы (в т.ч. и ExeInfo.hProcess) |
Сообщ.
#10
,
|
|
|
Коллеги, спасибо всем за советы!
Скопирую их и распечатаю. Проверять все буду на рабочей неделе. По результатам экспериментов обязательно отпишусь. |
Сообщ.
#11
,
|
|
|
Народ, немного извиняюсь!
Как выяснилось, один из вариантов решения моей задачи, предложенный здесь, изложен в классической книге Архангельского по Builder 6 (книга 1). (Ксатати, книга есть в Сети в *.pdf формате!) Собственно, взяв оттуда пример + здешние советы и решил свою проблему: bool res = CreateProcess(NULL, "MyHeavyTask.exe /Conf.txt", NULL, NULL, false, CREATE_NEW_CONSOLE | HIGH__PRIORITY_CLASS, NULL, NULL, &StartInfo, &ProcInfo)); while (1) { if (WaitForSingleObject(ProcInfo.hProcess, 500) == WAIT_0) break; } Собственно, в теле бесконечного цикла while один раз в 0.5 секунды можно контролировать управляющую программу. Так что вопрос с "зависанием" управляющей программы во время счета тяжелой программы MyHeavyTask.exe решен. Но тут же возник другой вопрос. А если дочерняя тяжелая задача MyHeavyTask.exe зависает (такое очень редко, но бывает), то как отследить этот момент? Может по тайм-ауту? Ведь нам примерно известно, сколько должна считаться тяжелая дочерняя задача. А может есть какой другой способ отследить, что MyHeavyTask.exe завершилась с кодом, не равным 0? P.S. Когда я запускал дочернюю задачу "умирающим" способом через spawnl(P_WAIT,... то spawnl возвращала -1 при зависании дочерней задачи. Так что рычаги есть, чтобы проследить код завершения дочерней задачи. Но вот как? |
Сообщ.
#12
,
|
|
|
Зависание и завершение с ошибкой - это разные вещи. Если прога завершается (не важно с каким кодом), то твой цикл ожидания на Wait.. по любому прерывается, и код завершения, как уже было сказано, можно получить через GetExitCodeProcess. А зависание - это когда прога не завершается, либо потому, что впадает в некий бесконечный цикл, либо "ждет у моря погоды", попав в некий deadlock (блокировку) на объектах синхронизации\ожидания. При этом и твой цикл с Wait.. будет продолжать крутиться, и GetExitCodeProcess будет возвращать STILL_ACTIVE. Поэтому никакого другого способа определить зависание, кроме как по тайм-ауту, нет.
PS: Если ты в цикле ожидания собираешься вызывать Application->ProcessMessages, чтобы твоя прога хотя-бы перерисовывалась вовремя, или юзер смог нажать кнопку Отмена, то лучше использовать функцию MsgWaitForMultipleObjects, которой при желании тоже можно задать тайм-аут (хотя на требования перерисовки и на юзерские клики она и так среагирует). |
Сообщ.
#13
,
|
|
|
Вот крайняя версия фрагмента моего кода управляющей программы для запуска тяжелого приложения:
int iTime; // счетчик времени DWORD iCod=14; // Код завершения процесса CreateProcess(NULL, "MyHeavyTask.exe /Conf.txt", NULL, NULL, false, CREATE_NEW_CONSOLE | HIGH__PRIORITY_CLASS, NULL, NULL, &StartInfo, &ProcInfo)); while (1) { // Бесконечный цикл. Отслеживаются события во время счета тяжелой программы DWORD ind = WaitForSingleObject(ProcInfo.hProcess, 500); // Раз в 0.5 секунды отслеживаются расчеты iTime++; // Увеличивается на 0.5 сек счетчик времени выполнения тяжелой программы UINT EndCode; if (ind==WAIT_OBJECT_0) { // Если тяжелая программа завершилась корректно, то GetExitCodeProcess(ProcInfo.hProcess, &iCod); // Получаем код завершения процесса break; // и выходим из бесконечного цикла } Application->ProcessMessages(); if (iTime >840) { // Обработка отбоя по тайм-ауту в 7 минут TerminateProcess(ProcInfo.hProcess, EndCode); iCod=14; break; } } В чем здесь проблема? Функция TerminateProcess не убивает дочерние зависшие процессы тяжелой программы. Поясню суть проблемы. Тяжелая программа MyHeavyTask.exe в свою очередь запускает на исполнение интерпретатор одной железки. Интерпретатор имеет тоже графический интерфейс, как и тяжелая задача. Если тяжелая задача виснет, а интерпретатор - нет, то TerminateProcess снимает с выполнения тяжелую задачу, но не интерпретатор. И когда управляющая задача запускает на счет следующий экземпляр тяжелой задача, то вычислительный процесс продолжается нормально. Однако, если зависает интерпретатор, то по тайм-ауту функцией TerminateProcess нормально снимается со счета тяжелая задача, но не висящий интерпретатор. И при запуске следующего экземпляра MyHeavyTask.exe прерывается нормальное течение расчетов, т.к. интерпретатор висит! Вот и возникает вопрос: как из управляющей программы снять со счета не только MyHeavyTask.exe, но и все ее дочерние процессы, включая интерпретатор. |
Сообщ.
#14
,
|
|
|
Цитата leo @ Вот и возникает вопрос: как из управляющей программы снять со счета не только MyHeavyTask.exe, но и все ее дочерние процессы, включая интерпретатор. Очевидно найти все дочерние процессы и закрыть их по отдельности. Если процессы имеют окна, то можно найти их с помощью FindWindow по заголовку\стилю окна. Если можно найти окна, то перед тем как использовать тяжелую артиллерию в виде TerminateProcess, можно попробовать закрыть главное окно посылкой сообщения WM_CLOSE или WM_SYSCOMMAND c параметром SC_CLOSE (через SendMessageTimeOut, чтобы твоя прога сама не зависла). Или определить id потока, которому принадлежит окно ф-ей GetWindowThreadProcessID и через PostThreadMessage послать ему сообщение WM_QUIT. Если это не помогает, то остается открывать процесс и вызывать TerminateProcess. Если не получается найти окно процесса, то можно перечислить дочерние процессы с помощью CreateToolhelp32Snapshot + Process32First\Next. Пример рекурсивного поиска и убийства дочерних процессов рассматривался недавно тут. (Там остались проблемы с "безопасным" убийством процесса через CreateRemoteThread, но если тебя устраивает TerminateProcess, то с созданием удаленного потока можно вообще не связываться) |
Сообщ.
#15
,
|
|
|
Цитата mkudritsky @ Вот и возникает вопрос: как из управляющей программы снять со счета не только MyHeavyTask.exe, но и все ее дочерние процессы, включая интерпретатор. Ctrl+Alt+Del Может стоить подумать как разгрузить "тяжелую" задачу? |