我有一个应用程序,其工作是启动和停止各种其他进程。
问题是,Qt应用程序不能完全停止。 Qt窗口closures,但进程仍在后台运行,直到调用TerminateProcess(),然后Qt应用程序退出而不清理。
我正在使用Microsoft提出的方法 。 即使是Qt源代码也使用这种方法来终止进程,除了它们也将WM_CLOSE发布到主线程。 我已经将它添加到了我的应用程序中,但它仍然closures了窗口,离开了这个过程。
我觉得有趣的是,如果我使用Windows任务pipe理器“结束任务”(不是“结束进程”),窗口closures,过程也结束了,所以我知道这是可能的。 如果我使用间谍++,我可以看到,主窗口和主线程都收到来自任务pipe理器和我的应用程序的WM_CLOSE消息,但只有通过使用任务pipe理器消息继续WM_DESTROY,WM_NCDESTROY等,并最终与过程结束。 这个问题只发生在Qt应用程序中。 Win32 / MFC等应用程序干净地终止使用我的应用程序。
你应该干净地closuresQt应用程序(假设Qt应用程序源不可用)?
– – – – 编辑 – – – –
以下是一些将重现问题的示例代码。 至less,我有兴趣知道其他人看到我看到的同样的问题。
示例代码启动CMake( 在这里下载 ),但任何Qt应用程序应该做的。
#include <Windows.h> #include <iostream> BOOL CALLBACK TerminateAppEnum(HWND hwnd, LPARAM pid); int _tmain(int argc, _TCHAR* argv[]) { char* processName = "C:\\Program Files (x86)\\CMake\\bin\\cmake-gui.exe"; //char* processName = "C:\\Windows\\Notepad.exe"; std::cout << "Creating process \"" << processName << "\"" << std::endl; STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); PROCESS_INFORMATION pi = {0}; BOOL success = CreateProcess(processName, "", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (success) { std::cout << "Press any key to cleanly terminate process..." << std::endl; std::cin.get(); std::cout << "Cleanly terminating process..." << std::endl; EnumWindows(TerminateAppEnum, (LPARAM)pi.dwProcessId); PostThreadMessage(pi.dwThreadId, WM_CLOSE, 0, 0); if (WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0) { std::cout << "Success! The process has terminated" << std::endl; } else { std::cout << "Failed! The process is still running" << std::endl; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { std::cout << "Unable to start process (Error " << GetLastError() << ")" << std::endl; } std::cout << "Press any key to exit..." << std::endl; std::cin.get(); return 0; } BOOL CALLBACK TerminateAppEnum(HWND hwnd, LPARAM pid) { DWORD dwPID; GetWindowThreadProcessId(hwnd, &dwPID); if (dwPID == (DWORD)pid) { PostMessage(hwnd, WM_CLOSE, 0, 0); } return TRUE; }
好的,解决了。
问题来自Qt创建一个顶层窗口QEventDispatcher
窗口的QEventDispatcher
。 按照Microsoft提出的过程,此窗口将获得WM_CLOSE消息,该消息将关闭该窗口及其线程。 之后,当应用程序的主窗口关闭时,不进行清理,进程保留在系统内存中。
有趣的是,通过使用任务管理器,QEventDispatcher 不会得到一个WM_CLOSE消息,因此保持活动状态,所以当主窗口产生一个WM_CLOSE消息时,进程就会干净地退出。 我只能假设在任务管理器的EnumWindowsProc回调中使用了类似IsWindowVisible的调用,与他们的文档相反。 虽然这个文档是十年前的最后一个评论!
添加到IsWindowVisible的调用中,使得该程序可以与所有的Qt应用程序一起工作,而其他非Qt应用程序似乎也很乐意继续处理这个更改。 为了完整性,我已经包含了更新的示例代码:
#include <Windows.h> #include <iostream> BOOL CALLBACK TerminateAppEnum(HWND hwnd, LPARAM pid); int _tmain(int argc, _TCHAR* argv[]) { char* processName = "C:\\Program Files (x86)\\CMake\\bin\\cmake-gui.exe"; //char* processName = "C:\\Windows\\Notepad.exe"; std::cout << "Creating process \"" << processName << "\"" << std::endl; STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); PROCESS_INFORMATION pi = {0}; BOOL success = CreateProcess(processName, "", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (success) { std::cout << "Press any key to cleanly terminate process..." << std::endl; std::cin.get(); std::cout << "Cleanly terminating process..." << std::endl; EnumWindows(TerminateAppEnum, (LPARAM)pi.dwProcessId); if (WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0) { std::cout << "Success! The process has terminated" << std::endl; } else { std::cout << "Failed! The process is still running" << std::endl; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { std::cout << "Unable to start process (Error " << GetLastError() << ")" << std::endl; } std::cout << "Press any key to exit..." << std::endl; std::cin.get(); return 0; } BOOL CALLBACK TerminateAppEnum(HWND hwnd, LPARAM pid) { DWORD dwPID; GetWindowThreadProcessId(hwnd, &dwPID); if (dwPID == (DWORD)pid) { if (IsWindowVisible(hwnd)) { PostMessage(hwnd, WM_CLOSE, 0, 0); } } return TRUE; }