par*_*ice 5 c++ windows winapi qt kill-process
我有一个应用程序,其工作是启动和停止各种其他进程.
问题是Qt应用程序不能完全停止.Qt窗口关闭,但进程仍然在后台运行,直到调用TerminateProcess(),然后Qt应用程序退出而不进行清理.
我正在使用Microsoft概述的这种方法.甚至Qt源也使用该方法来终止进程,除了它们还将WM_CLOSE发布到主线程.我已将其添加到我的应用程序中,但它仍然只是关闭窗口,离开了该过程.
我觉得有趣的是,如果我使用Windows任务管理器来"结束任务"(不是"结束进程"),窗口关闭,进程也结束,所以我知道这是可能的.如果我使用spy ++我可以看到主窗口和主线程都从任务管理器和我的应用程序接收WM_CLOSE消息,但只有使用任务管理器,消息继续到WM_DESTROY,WM_NCDESTROY等,最后结束进程结束.这个问题只发生在Qt应用程序中.Win32/MFC等应用程序使用我的应用程序干净地终止.
你应该如何干净地关闭Qt应用程序(假设Qt应用程序源不可用)?
- - - - 编辑 - - - -
这里有一些示例代码可以重现问题.至少,我有兴趣知道其他人是否看到了我所看到的同样问题.
示例代码启动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;
}
Run Code Online (Sandbox Code Playgroud)
好吧,解决了。
问题来自于 Qt 创建了一个顶级窗口——一个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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1610 次 |
| 最近记录: |