当前位置: 首页 > 知识库问答 >
问题:

终止Qt进程:Windows任务管理器在做什么而我没有?

欧阳嘉年
2023-03-14

我有一个应用程序,它的工作是启动和停止各种其他进程。

问题在于Qt应用程序不会完全停止。Qt 窗口关闭,但进程仍在后台运行,直到调用 TerminateProcess(), 然后 Qt 应用程序退出而不清理。

我正在使用微软概述的这种方法。甚至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;
}

共有1个答案

陈誉
2023-03-14

好了,解决了。

问题在于Qt创建了一个顶级窗口——一个< code>QEventDispatcher窗口。按照微软概述的过程,这个窗口得到一个WM_CLOSE消息,关闭那个窗口和它的线程。之后,当应用程序的主窗口关闭时,不进行任何清理,进程保留在系统内存中。

有趣的是,通过使用任务管理器,QEventDispatcher不会收到WM_CLOSE消息,因此保持活动状态,因此当主窗口发出WM_CLOSE消息时,进程会干净地退出。我只能假设在任务管理器的EnumWindowsProc回调中使用了对IsWindowViable之类的东西的调用,与它们的留档相反。尽管上次审查该留档是在十多年前!

添加对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;
}
 类似资料:
  • 问题内容: 是否有命令行参数来设置JVM向Windows任务管理器报告的标题?我所有的Java进程仅显示为“ javaw.exe”,并带有“ Java(TM)平台SE二进制文件”描述。如果我可以设置一些-param =“ This is eclipse”,那将是很棒的,这样我就可以很容易地将它们区分开。这样可以防止我经常杀死我的IDE,而不是例如tomcat。 问题答案: 您可以破解JVM二进制文

  • 根据Flink留档,存在两个维度来影响任务可用的资源量: 任务管理器的数量 任务管理器可用的任务槽数。 每个TaskManager有一个插槽意味着每个任务组在单独的JVM中运行(例如,可以在单独的容器中启动)。拥有多个插槽意味着更多的子任务共享同一个JVM。同一JVM中的任务共享TCP连接(通过多路复用)和心跳消息。它们还可以共享数据集和数据结构,从而减少每个任务的开销。 文档中有了这一行,您似乎

  • 问题内容: 考虑以下程序: 为什么它在本地终止而不在Playground终止?我的程序终止是否依赖未定义的行为? 问题答案: 该代码不能提供太多保证。它几乎完全依赖于围绕未定义行为的实现细节。 在大多数多线程系统中,不能保证一个线程中的更改不会出现障碍。您有一个goroutine,可以在另一个处理器上运行,总共将一个值写入一个没有人保证读取的变量。 将可以很容易地重写,因为从未有一个保证该变量的任

  • 昨天我在python中使用多重处理处理了大约2000万行的日志文件。 启动名为“producer”的进程,逐行读取文件并将其放入队列 代码在下面 结果很奇怪,工作完成后,消费者进程不会终止,并且主函数在连接()处被阻塞。 使用以下不同的套装和代码进行测试: 使用test_get_ip()而不进行多处理来处理大小日志文件,效果很好 那么,有什么问题?列表中有限制吗?有什么我错过的吗? 我的机器环境是

  • 我正在编写一个JavaFX应用程序,我的对象扩展任务提供了JavaFXGUI线程之外的并发性。 我的主要课程是这样的: 我的GUI控制器示例如下(略作抽象): 目前,我的任务只是进行睡眠并打印数字1到10: 我遇到的问题是,一旦任务完成,就好像启动任务的线程继续运行一样。因此,当我按下右上角的“X”退出JavaFX应用程序时,JVM继续运行,我的应用程序不会终止。如果你看一下我的主课,我已经把系统

  • 在我的生产服务器 (Windows 服务器 2012) 上,我安排了各种任务。我已经启用了任务计划程序历史记录,但它没有用。LastRunResult 我的每个任务都显示“上次运行的任务已由用户终止”,这意味着经过身份验证的程序已终止此任务。但是没有配置这样的程序可以停止所有这些任务。由于这个任务没有得到完成 1.我怎么能跟踪哪个程序/任务导致这种情况?这些计划任务之间存在巨大的时间差,那么问题可