优雅的 Win32 无窗口进程终止

Posted

技术标签:

【中文标题】优雅的 Win32 无窗口进程终止【英文标题】:Graceful Win32 windowless process termination 【发布时间】:2021-09-15 22:09:44 【问题描述】:

我正在开发一个用 C# 编写的控制台应用程序,我在其中触发 Application.Run() 来管理系统托盘。应用程序本身是无窗口的。

这是我遇到的挑战 - 当用户关闭应用程序时,我需要进行清理,并确保从系统托盘中删除应用程序图标。当我附加并分配了一个控制台窗口时,这很容易做到,因为我可以使用SetConsoleCtrlHandler

但是,当我没有分配和附加控制台窗口时,问题就开始了(因为应用程序大部分时间都是这样运行的)。我想优雅地从另一个进程中终止该进程,以便我可以在我的应用程序中调用 SetConsoleCtrlHandler 并进行清理。但是,我在 Windows 上找到的所有指导都是通过发送 WM_CLOSE 消息,这不适用,因为我没有任何可用于该应用程序的窗口。

所以,考虑到有问题的应用程序是使用CreateProcess 启动的,我有进程 ID、句柄和主线程 ID。

问题:我有没有办法优雅地告诉另一个应用程序终止而不调用TerminateProcess(这不会给任何清理余地)?

我想我可能需要实现一个命名管道,以便在这种情况下我可以在客户端应用程序和“服务器”之间进行通信,但是感觉有点过分了.

【问题讨论】:

我们过去的做法是让 process1 在启动时将其句柄传递给 process2。然后 process2 可以使用GetExitCodeProcess 来确定父级是否已退出。如果这更适合您的应用,您也可以等待父进程而不是轮询。 我认为如果你不设置它就不可能进行清理。您需要使用消息(喜欢但不是必需的WM_CLOSE)或实现自己的通信。 为什么不直接运行一个隐藏窗口来接收消息。我认为您需要在通知区域(又名系统托盘)中运行一个窗口。你的图标如何在没有窗口的情况下获取消息 如果你成功地将一个图标放入了 shell 通知区域,那么显然你必须为NOTIFYICONDATAW 提供了一个有效的HWND。是什么让您无法使用该窗口进行交流? @RetiredNinja 我认为从概念上讲这是有道理的,但挑战还在于父进程可能仍在运行。我只想从 _ 父级优雅地终止进程。 【参考方案1】:

我认为,你应该实现自己的沟通方式。恕我直言,最简单的方法是使用命名事件。控制台应用程序创建命名事件并有时检查它。外部应用程序设置事件以防退出第一个应用程序。 此方法仅适用于 Windows。

【讨论】:

一个名为EventWaitHandle的也可以用于Windows以外的操作系统。 将此标记为答案,因为这是我实现的唯一可靠的方法。

以上是关于优雅的 Win32 无窗口进程终止的主要内容,如果未能解决你的问题,请参考以下文章

win32(全屏)无边框窗口重叠任务栏

cef3嵌入win32无标题栏窗口,怎么来移动这个cef窗口

怎么使通过进程打开的win32程序窗口始终置顶

Win32 使用 SetCurrentProcessExplicitAppUserModelID 关联多个进程 在任务栏合并 WPF 多进程窗口

如何使用 Win32 API 阻止来自透明窗口的鼠标输入?

如何识别窗口是不是属于特定进程?