В прошлом посте я начал тему создания инсталляционного комплекта. Один из вопросов, который остался нераскрытым:
Ожидание завершения всех процессов, запущенных из программы установки.
Это должна быть простая программа, которая не требует установки дополнительных компонентов, поэтому язык C# не подходит (на компьютере может отсутствовать .NET Framework). Я выбрал для её реализации С++ с использованием статической библиотеки STL.
При запуске программа сразу запускает процесс setup.exe (исполняемый файл, получаемый в результате сборки Setup Project) и начинает наблюдение за ним:
//структура описывает запущенный процесс
struct PROC2WAIT
{ DWORD procID; //<идентификатор процесса HANDLE procH; //<хэндл процесса};//--------------------------------------------------------------------------//if (!::CreateProcess(setupPath, NULL, NULL, NULL, FALSE, 0U, NULL, NULL, &;sti, &pri))
{ int err = GetLastError(); throw exception("CreateProcess failed", err);}
PROC2WAIT rootProc = {0};rootProc.procH = pri.hProcess;rootProc.procID = pri.dwProcessId;//ожидаем завершения процесса и его потомковWaitProcTree(rootProc);Функция ожидания завершения процессов очень проста:
void WaitProcTree( PROC2WAIT rootProc)
{ list<;PROC2WAIT> pids; pids.push_back(rootProc); //продолжаем цикл, пока в наборе есть хотя бы один процессwhile (pids.size() >; 0)
{//ждем пока закроется хотя бы один
WaitAnyClose(pids); //добавляем новые процессы, которые были порождены завершенным или запущенными AddNewLeaves(pids); //удаляем из набора завершенные процессы RemoveClosed(pids); }}
Остальные функции не более сложные:
///ожидание завершения любого из процессовvoid WaitAnyClose( const list<PROC2WAIT> &pids )
{ HANDLE * phandles = new HANDLE[pids.size()]; int i = 0; for (list<PROC2WAIT>::const_iterator it = pids.begin(); it != pids.end(); it++)phandles[i++] = (*it).procH;
WaitForMultipleObjects(pids.size(), phandles, FALSE, INFINITE); delete[] phandles;}
//удаление из набора завершенных процессовvoid RemoveClosed( list<PROC2WAIT> & pids ) {list<PROC2WAIT>::iterator it = pids.begin();
while(it != pids.end()) { bool IsCompleted = (WaitForSingleObject((*it).procH, 0) == WAIT_OBJECT_0); if (!IsCompleted) {it++;
continue;}
list<PROC2WAIT>::iterator rem = it++;
CloseHandle(rem->procH);
pids.erase(rem);
}
}
На этом фоне чуть более сложной выглядит функция добавления в набор новых процессов, порожденных из уже запущенных. В основе её работы лежит использование функции CreateToolhelp32Snapshot, которая позволяет получить состояние запущенных процессов, с их последующим анализом и сравнением с имеющимся набором.
void AddNewLeaves( list<PROC2WAIT> & pids ) {HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0U);
if (hsnap == INVALID_HANDLE_VALUE)throw exception("CreateToolhelp32Snapshot failed", GetLastError());
PROCESSENTRY32 ProcEntry = {0}; ProcEntry.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hsnap, &ProcEntry)) { do {CompareID x(ProcEntry.th32ParentProcessID);
list<PROC2WAIT>::iterator hasparent = find_if(pids.begin(), pids.end(), x);
if (hasparent != pids.end()) { PROC2WAIT p = {0}; p.procH = OpenProcess(SYNCHRONIZE, FALSE, ProcEntry.th32ProcessID);p.procID = ProcEntry.th32ProcessID;
if (p.procH != NULL)pids.push_back(p);
}
} while (Process32Next(hsnap, &ProcEntry));}
}
Комментариев нет:
Отправить комментарий