Очень часто возникает необходимость вызывать из работающего приложения другие исполняемые модули. |
![]() |
Добавил(а) microsin | |||||||||
В таких случаях возможны несколько случаев, определяемые сутью решаемых задач, а именно: требуется ли ожидание завершения работы порожденного процесса, и если требуется, то в синхронном или асинхронном режиме? Рассмотрим несколько случаев. 1. Работа приложения не должна продолжаться, пока не закончит работу порожденный процесс: самый неинтересный вариант. Для запуска процесса можно воспользоваться функциями семейства spawn... c параметром P_WAIT. 2. Приложение должно продолжать работу, не обращая внимания на поведение порожденного процесса: ненамного интереснее. Используются либо те же spawn... функции, либо ShellExecute, либо WinExec. 3. Вариант следующий: после вызова внешней задачи приложение выполняет какие-либо действия, а потом ожидает завершения порожденного процесса. И тут пригодятся функции spawn... , но уже с параметром P_NOWAIT или P_DETACH. В таком случае в системе сохраняются идентификаторы дочерних процессов, завершение которых становится возможным отслеживать. Для этого применяются функции wait и cwait.
Если параметр statloc не NULL, то он указывает на целое, представляющее собой статус завершения порожденного процесса. При нормальном его завершении биты этого целого означают следующее: биты 0 - 7 Нули биты 0 - 7 1 неисправимая ошибка 4. Напоследок, самое любопытное. Допустим, что программа должна отследить завершение порождённого процесса, но при этом не должна приостанавливать своей работы (как это происходит в случае использования функций wait и cwait). Я предлагаю использовать следующий подход: необходимо сохранить идентификатор порождённого процесса. Он возвращается функциями spawn... или может быть получен из структуры PROCESS_INFORMATION, передаваемой в функцию CreateProcess, которая, кстати, является рекомендованной к применению в Windows'9x. Далее необходимо подключить обработчик события OnIdle класса TApplication. STARTUPINFO StartUp={sizeof (STARTUPINFO), NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, STARTF_USESHOWWINDOW, SW_HIDE, 0, NULL, NULL, NULL}; PROCESS_INFORMATION Inform;//Заполняем структуры, необходимые для порождения // нового процесса ...int res=CreateProcess(NULL, RunAllName.c_str(), NULL, NULL, 0, REALTIME_PRIORITY_CLASS, NULL, RootDir.c_str(), &StartUp, Inform);if(res) {// если процесс корректно порождён ... fmMain->hProcess=Inform.hProcess; //сохр. handler порожденного процесса ... Application->OnIdle=&fmMain->IdleProc; //подключаем обработчик OnIdle ... } Разумеется, этот обработчик должен быть заранее подготовлен и иметь, например, следующий вид: void _fastcall TfmMain::IdleProc(TObject *Sender,bool& Done) { unsigned long test; GetExitCodeProcess(hProcess,&test); //получаем статус процесса if (test!=STILL_ACTIVE){ // если завершён............ hProcess=0; //обнуляем идентификатор DeleteFile(RootDir+TempFileName );//удаляем временный файл miRunSearch->Enabled=true; miGenerate->Enabled=true; miRunBatch->Enabled=true; //активизируем пункты меню sbBar->SimpleText="Done!!!"; Application->OnIdle=NULL; // отключаем ненужный теперь обработчик Stat=new TfmStat(Application); Stat->lbTotProc->Caption=Processes; Stat->lbCurProc->Caption=ProcessName; Stat->CurTime=Stat->CurTime.CurrentDateTime(); //выводим окно статистики Stat->lbTime->Caption=(Stat->CurTime-ProcBeg).TimeString() + " :: " + (AnsiString)(((int)((double) (Stat2->CurTime - ProcBeg)*24*3600*100) )%100); Stat->lbTime->Enabled=true; Stat->lbTimeEl->Enabled=true; Stat->ShowModal(); delete Stat; Stat=NULL; if (ShowRep) //и если надо, показываем отчёт {...} if (RepType==Substitutions) OpenReport(ReportName); {...} } } Такой подход даёт наиболее гибкие возможности по контролю порождённых процессов и может свободно применяться в средах Delphi и C++ Builder. |