使用 Win32 监视打开的程序
我搜索过网络和各种论坛,但我找不到一件事,如何持续监视打开的程序,然后在被监视的程序发生问题时关闭另一个程序(不是被监视的程序)。
例如,假设有一个已打开的记事本窗口,然后用户或某些其他程序打开 Windows 资源管理器窗口。我想知道如何在不与 Windows 资源管理器窗口交互的情况下关闭记事本窗口(除了意识到它确实已打开),以及如何在用户关闭 Windows 资源管理器窗口时关闭记事本窗口。
提前致谢! :D
I've searched the web, and various forums, but I can't find one thing, how to continually monitor open programs and then close another program (not the one being monitored) if something happens to the program being monitored.
For example, say that there is an already open Notepad window, and then the user or some other program opens a Windows Explorer window. I want to know how to close the Notepad window without interacting with the Windows Explorer window (other than realizing that it is indeed open), as well as closing the Notepad window if the user closes the Windows Explorer window.
Thanks in advance! :D
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 Windows 上,您可以使用 PSAPI< /a> (进程状态 API)了解进程何时启动和终止。 EnumProcesses 函数可以为您提供此信息。
确定进程终止的更可靠方法(因为进程 ID 可以重用)是等待其进程句柄(您将需要
SYNCHRONIZE
访问权限),您可以使用 OpenProcess 以及从以下位置获取的进程 id枚举进程。要终止进程,始终有 终止进程。要调用 TerminateProcess,您需要一个具有
PROCESS_TERMINATE
访问权限的进程句柄。所有这些都假设您拥有对要终止的进程执行这些操作所需的权限。On windows, you can use PSAPI (The Process Status API) to know when processes are started and terminate. The EnumProcesses function can give you this information.
A more reliable method to determine that a process terminated (since process ids can be reused) is to wait on its process handle (you will need the
SYNCHRONIZE
access right) which you can obtain using OpenProcess and the process' id obtained from EnumProcesses.To terminate a process, there is always TerminateProcess. To call TerminateProcess, you will need a handle to the process with the
PROCESS_TERMINATE
access right. All of this assumes that you have the privileges needed to perform these actions on the process to be terminated.需要注意的一件事是,进程和程序(或者至少用户所认为的程序)不一定是同一件事。
如果您使用 PSAPI 获取所有正在运行的进程的列表,您将看到许多与打开的窗口根本不对应的后台进程。在某些情况下,单个进程可以打开多个顶级窗口。因此,虽然您有像记事本这样的简单情况,其中一次 notepad.exe 进程对应于一个记事本窗口,但您也有这样的情况:
使用 TerminateProcess 可能不是关闭应用程序的最佳方法:它并不直接等同于单击关闭按钮。它立即强行终止整个进程,不给它任何清理的机会。如果您在 Word 上执行此操作,当它重新启动时,它将进入“恢复模式”,并且表现得就像上次没有完全关闭一样。如果进程停止响应,最好将其作为最后的手段。另外,如果您在 Word 或 Explorer 之类的进程上终止进程,您最终将关闭该进程拥有的所有窗口,而不仅仅是一个特定的窗口。
考虑到所有这些,如果您想本质上编写某种程序管理器,那么最好采用以窗口为中心的方法,而不是以进程为中心的方法。监视顶级应用程序窗口,而不是监视正在运行的进程。
有多种方法可以监听窗口的变化;使用 EVENT_CREATE/DESTROY 的 SetWinEventHook 是侦听正在创建或销毁的 HWND 的一种方法(您需要在这里进行过滤,因为它会告诉您所有 HWND - 以及更多! - 但您只关心顶级的 HWND,并且只有应用程序)。 SetWindowsHookEx 可能还有其他可以在这里使用的选项 (WH_CBT)。您还可以使用 EnumWindows 列出当前存在的窗口(同样,您需要过滤掉拥有的对话框和工具提示、当前不可见的 HWND 等)。
给定 HWND,如果需要,您可以使用 GetWindowThreadProcessId 获取进程信息。
要关闭窗口,发送 WM_SYSCOMMAND/SC_CLOSE 是首先尝试的最佳方法:这更接近单击关闭按钮,并且它使应用程序有机会进行清理。请注意,某些应用程序会显示“您确定要关闭吗?”如果您最近没有保存过,则会出现对话框 - 再次强调,这与用鼠标单击关闭按钮是一致的。
One thing to be aware of is that processes and programs - or at least what the user regards as a program - are not necessarily the same thing.
If you use the PSAPI to get a list of all the processes running, you'll see a lot of background process that don't correspond to open windows at all. There's also cases where a single process can have multiple top-level windows open. So while you have simple cases like notepad where once notepad.exe process corresponds to one Notepad window, you also have cases like:
Using TerminateProcess is perhaps not the best way to close an app: it's not directly equivalent to clicking the close button. It forcibly terminates the entire process there and then, without giving it any chance to clean up. If you do this on Word, when it restarts, it will go into 'recovery mode', and act as though it hadn't shut down cleanly the last time. It's best left as a last resort if a process has stopped responding. Also, if you TerminateProcess on a process like Word or Explorer, you'll end up closing all windows owned by that process, not just one specific one.
Given all of this, if you want to essentially write some sort of program manager, you might be better off taking a window-centric approach rather than a process centric one. Instead of monitoring running processes, monitor top-level application windows.
There are several ways to listen for changes to windows; SetWinEventHook with EVENT_CREATE/DESTROY is one way to listen for HWNDs being created or destroyed (you'll need to do filtering here, since it will tell you about all HWNDs - and more! - but you only care about top-level ones, and only app ones at that). SetWindowsHookEx may have other options that could work here (WH_CBT). You can also use EnumWindows to list the windows currently present (again, you'll need to filter out owned dialogs and tooltips, currently invisible HWNDs, etc).
Given a HWND, you can get process information if needed by using GetWindowThreadProcessId.
To close a window, sending WM_SYSCOMMAND/SC_CLOSE is the best thing to try first: this is closer to clicking the close button, and it gives the app a chance to clean up. Note that some apps will display a "are you sure you wish to close?" dialog if you haven't saved recently - again, it's consistent with clicking the close button with the mouse.
在 Windows 上执行此操作的最知名方法是使用 进程状态 API。您可以使用此 API 枚举进程 然而,这个 API 很烦人,因为它不能保证您获得完整的列表或进程。
枚举进程的更好方法是使用工具帮助库,其中包括一种获取完整任意给定时间系统中所有进程的快照 。
The most well-known way of doing this on Windows is to use the Process Status API. You can use this API to enumerate processes However, this API is annoying in that it doesn't guarantee you get the full list or processes.
A better way to enumerate processes is using the Tool Help Library, which includes a way to take a complete snapshot of all processes in the system at any given time.
您需要 Microsoft PSAPI(进程 API),例如要查看打开的进程,您可以使用 openProcess 函数。
You need the Microsoft PSAPI (Processes API), for example to see the open processes you can use the openProcess function.