【问题标题】:How can I wait for an application launched by another application launched by my application Qt/C++如何等待由我的应用程序 Qt/C++ 启动的另一个应用程序启动的应用程序
【发布时间】:2015-06-04 12:01:54
【问题描述】:

我正在 Qt 5.4 中创建一个 Windows 添加/删除程序应用程序,我正在为解决一个小“难题”而发疯:

我的应用程序 (APP_0) 运行另一个应用程序 (APP_1) 并等待此 APP_1 直到它终止。

APP_1 是一个卸载程序(即uninstall.exe),我没有APP_1 的源代码,只有我的Qt APP_0。

APP_1,而不是执行卸载工作,它只是将自身复制到文件系统中的某个位置(我看到的是 Au_.exe,但其他应用程序可以使用不同的名称和位置),运行这个自身的副本 (APP_2) 并终止。

APP_2 有一个 GUI,我正在等待(卸载)的作业需要运行 APP_2 的最终用户。

在这种情况下,我的应用程序 (APP_0) 会立即停止等待 APP_1(因为它会启动 APP_1 并等待 APP_1)​​。但要正常工作,显然,我需要知道 APP_2 何时终止...

所以问题是: 有没有办法(使用一些技术(挂钩?))知道 APP_2 是否以及何时终止?

注意:考虑到标准的 Windows 添加/删除程序实用程序成功地完成了这项工作(它似乎在等待 APP_2)。您可以对此进行测试,例如,安装 Adob​​e Digital Edition。它的卸载程序 (uninstall.exe) 将自身复制到 User_Local_Temp 文件夹中的一个新文件夹中作为 Au_.exe,运行它并终止。但操作系统实用程序成功等待 Au_.exe 并且只有在它终止后才会刷新已安装程序的列表。

如果这种技术(uninstall.exe 总是使用相同的名称 (Au_.exe) 将自身复制到某个地方),那么问题显然可以非常简单地解决。但我不认为复制的卸载程序的名称总是相同的,而且我不喜欢假设我不确定的东西是真实的。

在此先感谢

【问题讨论】:

  • 将 APP_1 分配给 Job Object 并等待作业终止。
  • 感谢您的回答!我会试试你的建议。我认为这可能是正确的方法...再次感谢

标签: c++ windows qt uninstallation


【解决方案1】:

感谢 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();

    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    相关资源
    最近更新 更多