Windows — Как я могу ждать приложение, запущенное другим приложением, запущенным моим приложением Qt / Stack Overflow

Я создаю приложение Windows для установки и удаления программ в Qt 5.4 и схожу с ума, решая небольшую «головоломку»:

Мое приложение (APP_0) запускает другое приложение (APP_1) и ждет этого APP_1, пока оно не завершится.

APP_1 является деинсталлятором (т.е. uninstall.exe), и я не являюсь исходным кодом APP_1, только моего Qt APP_0.

APP_1 вместо того, чтобы выполнять работу по удалению, просто копирует себя в файловую систему (я видел как Au_.exe, но другие приложения могут использовать другие имена и местоположения), запускает эту копию себя (APP_2) и завершает работу.

APP_2 имеет графический интерфейс пользователя, и ожидаемое задание (удаление) требуется конечному пользователю работающего APP_2.

В этой ситуации мое приложение (APP_0) перестает ожидать APP_1 практически сразу (потому что оно запускает APP_1 и ожидает APP_1). Но для правильной работы, очевидно, мне нужно знать, когда APP_2 завершается …

Итак, вопрос:
Есть ли способ (используя некоторые методы (перехват?)), чтобы узнать, если и когда APP_2 завершается?

Примечание. Учтите, что стандартная утилита Windows «Установка и удаление программ» выполняет свою работу успешно (кажется, она ожидает APP_2). Вы можете проверить это, например, установив Adobe Digital Edition. Его деинсталлятор (uninstall.exe) копирует себя в новую папку в папке User_Local_Temp под именем Au_.exe, запускает его и завершает работу. Но утилита ОС успешно ждет Au_.exe и только после ее завершения обновляет список установленных программ.

Если этот вид техники (uninstall.exe копирует себя куда-то ВСЕГДА с тем же именем (Au_.exe)), проблема может быть решена, очевидно, очень просто. Но я не думаю, что имя скопированного деинсталлятора всегда одинаково, а также я не люблю предполагать, что вещи, в которых я не уверен, реальны.

Спасибо заранее

0

Решение

Благодаря предложению IInspectable (см. Его комментарий … и большое спасибо, парень!) Я создал функцию, которая решает мои проблемы! Я поделюсь здесь этой функцией, которая может быть полезна другим людям с той же (или похожей) проблемой.

Для моих нужд функция получает в качестве параметра индекс элемента, который необходимо удалить (из QList), и получает строку удаления (например: C: \ ProgramFiles \ MyApp \ uninstall.exe).

Затем с помощью этой строки удаления я создам процесс (CreateProcess) и помещу его дескриптор в объект задания, так что моя функция будет ожидать всех процессов, запущенных этим процессом.

Сама функция довольно проста и может быть улучшена.
Обратите внимание, что процесс ДОЛЖЕН быть создан с параметром CREATE_BREAKAWAY_FROM_JOB, в противном случае AssignProcessToJobObject завершится с ошибкой «Отказано в доступе».

void MainWindow::uniButtonClick(int idx)
{
QMessageBox::StandardButton reply;
QMessageBox::StandardButton err;

reply = QMessageBox::question(this, "Uninstall/Change", "Uninstall " +
ip[idx].displayName +"?\r\n\r\n" + ip[idx].uninstallString,
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes)
{
//QString s = "C:\\windows\\notepad.exe"; // Just to test Job assignment and createprocess
QString s = ip[idx].uninstallString; // the real uninstaller string

QString jobName = "MyJobObject";

try
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
PJOBOBJECT_BASIC_PROCESS_ID_LIST pList;
HANDLE hProcess;
BOOL bJobAllEnd;ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field

wchar_t* path;
path = (wchar_t*) malloc (sizeof(wchar_t)*s.length()+1);
s.toWCharArray(path);
path[s.length()]=0; // Null terminate the string

// Create the process with CREATE_BREAKAWAY_FROM_JOB to overcome the AccessDenied issue on AssignProcessToJobObject.
if(CreateProcess(NULL, path, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB|CREATE_SUSPENDED, NULL, NULL,&StartupInfo, &ProcessInfo))
{
pList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)GlobalAlloc(GMEM_FIXED, 10000);

HANDLE jobObj = CreateJobObject(NULL, (const wchar_t*)jobName.utf16());

if (AssignProcessToJobObject(jobObj, ProcessInfo.hProcess) != 0)
{
ResumeThread(ProcessInfo.hThread); // Process assigned to JobObjext, resume it now

do
{
QueryInformationJobObject(jobObj, JobObjectBasicProcessIdList, pList, 10000, NULL);

bJobAllEnd = TRUE;

for(DWORD i=0; i<pList->NumberOfProcessIdsInList; i++)
{
hProcess = OpenProcess(SYNCHRONIZE, FALSE, pList->ProcessIdList[i]);
if(hProcess != NULL)
{
CloseHandle(hProcess);
bJobAllEnd = FALSE;
}
}

Sleep(500);
} while(!bJobAllEnd);}
else
qDebug() << "AssignProcess to Job failed: error = " << QString::number(GetLastError());

GlobalFree(pList);
CloseHandle(jobObj);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}

}
catch(QString error)
{
QMessageBox::critical(this, "File not found!", "The requested uninstaller doesn't exists", QMessageBox::Ok);

}// refresh list
handleButton();

}

}
1

Другие решения


По вопросам рекламы [email protected]