Ending the Qt process: what makes Windows Task Manager the way I am?

I have an application whose task is to start and stop various other processes.

The problem is that Qt applications do not terminate cleanly. The Qt window closes, but the process still runs in the background until TerminateProcess () is called, and then the Qt application exits without clearing.

I use this method as described by Microsoft. Even Qt source uses this method to terminate processes, except that they also send WM_CLOSE to the main thread. I added this to my application, but it still just closes the window, leaving the process.

Interesting is that if I use the Windows task manager to โ€œEnd the taskโ€ (โ€œDo not end the processโ€), the window closes and the process also ends, so I know that this is possible. If I use spy ++, I see that the main window and the main thread receive WM_CLOSE messages from the task manager and my application, but only with the help of the task manager the messages continue until WM_DESTROY, WM_NCDESTROY, etc. And end with the end of the process. This problem only occurs with Qt applications. Win32 / MFC applications, etc. Stop using my application.

How should you completely close Qt applications (suppose the source of the Qt application is not available)?

-------- -------- Edit

Here is an example of code that will reproduce the problem. At least, I would be interested to know if other people see the same problem as me.

The sample code launches CMake ( download here ), but any Qt application should do.

#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; } 
+5
source share
1 answer

Ok, I decided.

The problem arises because Qt creates a top-level window - the QEventDispatcher window. Following the procedure described by Microsoft, this window receives a WM_CLOSE message that closes this window and its stream. After that, when the main application window is closed, cleaning is not performed, and the process remains in the system memory.

Interestingly, when using the task manager, QEventDispatcher does not receive the WM_CLOSE message, therefore it remains active, and therefore, when the WM_CLOSE message appears in the main window, the process crashes. I can only assume that the IsWindowVisible call is used in the EnumWindowsProc callback in the task manager, as opposed to the documentation . Although this documentation was last reviewed more than ten years ago!

Adding IsWindowVisible to the call makes the program work with all Qt applications, and other non-Qt applications seem happy to continue working with this change. For completeness, I have included an updated code example:

 #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; } 
+2
source

Source: https://habr.com/ru/post/1206105/


All Articles