简体   繁体   English

我如何等待由我的应用程序Qt / C ++启动的另一个应用程序启动的应用程序

[英]How can I wait for an application launched by another application launched by my application Qt/C++

I'm creating a Windows Add/Remove Programs application in Qt 5.4 and I'm becaming crazy to solve a little "puzzle": 我正在Qt 5.4中创建一个Windows“添加/删除程序”应用程序,而我正疯狂地解决了一些“难题”:

My application (APP_0) runs another application (APP_1) and waits for this APP_1 until it terminates. 我的应用程序(APP_0)运行另一个应用程序(APP_1)​​,并等待此APP_1终止。

APP_1 is an uninstaller (ie uninstall.exe) and I've not the source code of the APP_1, just of my Qt APP_0. APP_1是一个卸载程序(即,uninstall.exe),我不是我的Qt APP_0的APP_1的源代码。

APP_1, instead of doing the uninstall job, it simply copies itself somewhere in the filesystem (I saw as Au_.exe but other apps could use different names and locations), runs this copy of itself (APP_2) and terminates. APP_1而不是执行卸载工作,它只是将自身复制到文件系统中的某个位置(我看到为Au_.exe,但其他应用程序可以使用不同的名称和位置),运行其自身的副本(APP_2)并终止。

The APP_2 has a GUI and the job I'm waiting for (uninstall) is demanded to the final user of the running APP_2. APP_2具有GUI,正在运行的APP_2的最终用户需要我正在等待的任务(卸载)。

In this situation my application (APP_0) stops waiting for APP_1 pratically immediately (because it launches APP_1 and waits for APP_1). 在这种情况下,我的应用程序(APP_0)会立即停止等待APP_1(因为它启动了APP_1并等待APP_1)​​。 But to work properly, obviously, I need to know instead when APP_2 is terminated... 但是显然,要正常工作,我需要知道APP_2何时终止...

So the question is: is there a way (using some techniques (hooking?)) to know if and when APP_2 terminates? 因此,问题是:是否有一种方法(使用某些技术(挂钩)?)来知道APP_2是否以及何时终止?

Note: Consider that the standard Windows Add/Remove Programs utility does the job successfully (it seems it waits for APP_2). 注意:请考虑使用标准的Windows添加/删除程序实用程序成功完成了该作业(似乎正在等待APP_2)。 You can test this, for example, installing Adobe Digital Edition. 您可以对此进行测试,例如,安装Adobe Digital Edition。 Its uninstaller (uninstall.exe) copies itself into a new folder in the User_Local_Temp folder as Au_.exe, runs it and terminates. 其卸载程序(uninstall.exe)将自身作为Au_.exe复制到User_Local_Temp文件夹中的新文件夹中,然后运行它并终止。 But the OS utility successfully waits for Au_.exe and only after it terminates refreshes the list of installed programs. 但是OS实用程序成功等待Au_.exe,并且只有在终止后才会刷新已安装程序的列表。

If this kind of technique (uninstall.exe copies itself somewhere ALWAYS with THE SAME name (Au_.exe) ) the problem could be resolved, obviously, very simply. 如果这种技术(uninstall.exe始终将其自身复制到具有相同名称(Au_.exe)的某处),则可以很简单地解决此问题。 But I don't think that the name of the copied uninstaller is always the same and also I don't like to assume things I'm not sure are real. 但是我不认为复制的卸载程序的名称总是相同的,而且我也不喜欢假设不确定的事情是真实的。

Many thanks in advance 提前谢谢了

Thanks to IInspectable's suggestion (see his comment... and many thanks guy!) I created a function which solves my problems! 感谢IInspectable的建议(请参阅他的评论……非常感谢!),我创建了一个解决我的问题的函数! I'll share here this function which could be useful to other people with the same (or similar) problem. 我将在这里分享此功能,该功能可能对其他遇到相同(或相似)问题的人有用。

For my needs, the function receives as parameter the index of the item to be uninstalled (from a QList) and gets the uninstall string (for example: C:\\ProgramFiles\\MyApp\\uninstall.exe). 对于我的需求,该函数从QList接收要卸载的项目的索引作为参数,并获取卸载字符串(例如:C:\\ ProgramFiles \\ MyApp \\ uninstall.exe)。

Then with this uninstall string, I'll create a process (CreateProcess) and put its handle into a Job Object, so that my function will wait for all the processes ran by this process. 然后,使用此卸载字符串,我将创建一个进程(CreateProcess)并将其句柄放入作业对象,以便我的函数将等待该进程运行的所有进程。

The function itself is pretty simple and can be improved. 该函数本身非常简单,可以改进。 Notice that the process MUST be created with the CREATE_BREAKAWAY_FROM_JOB option, otherwise the AssignProcessToJobObject will fail with a "Access Denied" error. 请注意,必须使用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();

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Qt 应用程序可以关闭另一个已经启动的应用程序吗? - Can a Qt Application close another already launched application? 调试从Linux中的另一个C ++应用程序启动的python脚本 - Debugging of python script launched from another C++ application in Linux 我们如何判断C ++应用程序是否作为Windows服务启动? - How do we tell if a C++ application is launched as a Windows service? 如何使用 C++ 在 Windows 中确定应用程序是否已启动? - How to determine an application is already launched or not in windows using C++? 在终端上为通过C ++中的exec启动的应用程序处理用户输入 - Handing user input on terminal for application launched via exec in C++ 如何跟踪 C++14 中的控制台应用程序已启动的次数? - How to track the number of times my console application in C++14 has been launched? 我如何从 qt 应用程序 (c++) 打开可执行文件 - How can i open an executable from an qt application (c++) 捆绑用于OSX的Qt 5.4应用程序在启动时崩溃 - Qt 5.4 application bundled for OSX crashes when launched 重点介绍从C ++ Shell扩展启动的C#UI应用程序 - Give focus to a C# UI Application launched from a C++ Shell Extension 如何从另一个C ++控制台应用程序启动/结束C ++控制台应用程序? - How can I start/end a C++ Console Application from another C++ Console Application?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM