Win32:获取其他应用程序关闭/退出的消息通知

4
我的应用程序需要监控系统上所有正在运行的应用程序。有没有一种方法可以在每个应用程序exe退出时得到通知?
我找到的方法如下:
1)使用PSAPI函数以频繁的间隔获取运行中exes的列表。在每次轮询时,与之前的列表进行比较,找出已退出的应用程序/进程。 缺点:需要不断轮询,会占用CPU时间。
2)设置WM_CLOSE消息的全局钩子:使用此方法,当任何应用程序通过标题栏上的关闭按钮关闭时,我将能够收到通知。
缺点: (-)并非所有应用程序都会生成WM_CLOSE消息(例如:Total Video Player Exe) (-)如果应用程序是通过“退出”菜单或按钮(例如:文件->退出)关闭的,则无法捕获该消息。
是否还有其他更好的方法我可能忽略了?请给予建议。
4个回答

10

我在使用 WaitForSingleObjects 和 WaitForMultipleObjects 时都遇到了 ERROR_ACCESS_DENIED (0x5) 错误。你有什么想法,为什么会出现这种情况,我做错了什么吗? - santahopar
我只能猜测:也许是请求了太多的访问权限?SYNCHRONIZE 应该足够了。也许您的用户上下文不允许监视此进程(例如,普通用户无法访问系统进程。我相信即使管理员用户也需要管理员权限才能访问这些进程)。 - Serge Wautier
问题实际上是权限问题,所以你是对的Serge - appTranslator。我使用了PROCESS_ALL_ACCESS标志。 - santahopar

2
你可以尝试使用RegisterShellHookWindow() API,并过滤HSHELL_WINDOWCREATED和HSHELL_WINDOWDESTROYED消息来获得通知。当然,这只能让你收到关于有窗口的应用程序的通知。

1
我会尽量避免注册全局钩子,除非没有其他选择。 - i_am_jorf

1
我最近遇到这个问题并找到了解决方法,想要和大家分享。我们应该正确地获取进程的句柄,而不是使用WaitForSingleObject。我建议使用RegisterWaitForSingleObject函数。使用此函数时,您需要提供一个回调函数,每当进程退出时,都会调用该回调函数。这比在线程中调用WaitForSingleObject更好。在代码中调用WaitForSingleObject本身会导致您的代码等待进程退出。以下是调用它的示例:
RegisterWaitForSingleObject(&waitHandle, processHandle, ProcessTerminatedCallback, param, INFINITE, WT_EXECUTEONLYONCE);

参数:

[out]waitHandle - 为您创建的新句柄。请注意,您不能使用此句柄调用CloseHandle,但是如果您想要等待它,可以使用它。

[in] processHandle - 您需要自己获取的进程句柄

[in] ProcessTerminatedCallback - 进程退出时将调用的回调函数

[in] param - 将传递给回调函数的LPVOID参数

[in] INFINITE - 要么无限等待,要么等待指定的时间,请查阅MSDN获取更多信息

[in] WM_EXECUTEONLYONCE - 仅调用一次回调函数。请查阅MSDN获取更多信息


这样做会不会只在输入句柄的进程结束时显式触发回调函数?还是还有其他事件会触发它,因为“WaitForSingleObject”似乎含糊不清? - oblivioncth
@oblivioncth,即使它崩溃了也会被调用。如果进程只是挂在那里,它显然不会被调用。为此,您可能需要引入一些心跳机制,但是为此您必须访问进程的代码。 - santahopar
谢谢,这很有用;然而我的困惑在于你是如何确定此函数首次发出目标应用程序关闭的信号。文档基本上只提到当“指定对象处于信号状态”时调用回调函数,这听起来可能是任意数量的信号,因为它太过模糊。我只是想确保这仅在进程结束时(无论原因)才发出信号。 - oblivioncth
@oblivioncth,我可以保证它能够正常工作并且表现得非常好。我在Windows服务中使用它来监控某些使用其API的应用程序。这些应用程序会在服务中存储大量数据,而我实现的这个模块可以在应用程序崩溃或忘记在退出前清理它们正在使用的内存时清理内存。这些内存是在Windows服务空间中分配的。 - santahopar
我相信你对这个函数的效果是正确的,但是我想在官方文档中找到描述这些效果的语句,以防有关使用的任何注释或警告。最终我在这里找到了:https://learn.microsoft.com/en-us/windows/win32/sync/synchronization-objects -> 在进程下面:“当进程正在运行时,其状态设置为未发出信号,并在进程终止时设置为已发出信号。” 没有给出其他细节,所以似乎很简单明了。 - oblivioncth

-1

> 有没有我错过的其他更好的方法?

有的,可以看看Win32组(系统通知,无需任何钩子)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接