【问题标题】:Gracefully kill Chrome for Windows with Python使用 Python 优雅地杀死 Chrome for Windows
【发布时间】:2019-07-19 07:21:15
【问题描述】:

我一直在尝试确定一种使用 Python 优雅地关闭 Chrome(和其他进程)的方法。我已经尝试了几种方法,但所有方法都导致 Chrome 显示一条消息,指出“Chrome 没有正确关闭”。带有恢复按钮。当您从 Windows 中的任务管理器关闭程序时,不会发生这种情况。我编写了一个程序,利用 Falcon 提供 API 访问以关闭“托管”程序。代码不相关,但这是我尝试过的方法,它们可以很好地关闭 Chrome,但效果不佳。

def stop_app(app_exe):
    for process in psutil.process_iter():
        if process.name() == app_exe:
            process.terminate()

替代:

for process in psutil.process_iter():
    if process.name() == app_exe:
        children = process.children(recursive=True)
        children.append(process)
        for p in children:
            p.send_signal(signal.CTRL_BREAK_EVENT)

我也试过用 kill() 代替 terminate(),各种信号类型(Windows 真的只支持三种,CTRL_BREAK_EVENT、CNTL_C_EVENT、SIGTERM)。

我也尝试过使用 win32 库,但遇到了同样的问题。 Win32 也不是平台无关的,我发现 win32/wmi 库在查找正在运行的 Windows 进程时会使用大量系统资源。 psutil 库允许与平台无关,并且在遍历 Windows 进程时不会出现相同的性能问题。这是代码。

c = wmi.WMI()
for process in c.Win32_Process():
    if process.Name == app_exe:
        process.Terminate()

有人尝试过类似的方法并提出解决方案吗?

根据 CristiFati 建议的快速解决方案。

def enumWindowsProc(hwnd, lParam):
    if (lParam is None) or ((lParam is not None) and 
          win32process.GetWindowThreadProcessId(hwnd)[1] == pid)):
        text = win32gui.GetWindowText(hwnd)
        if text:
            wStyle = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE)
            if wStyle & win32con.WS_VISIBLE:
                win32api.SendMessage(hwnd, win32con.WM_CLOSE)


def stop_app(app_exe):
    for process in psutil.process_iter():
        if process.name() == app_exe:
            win32gui.EnumWindows(enumWindowsProc, process.pid)

【问题讨论】:

    标签: python browser wmi pywin32 psutil


    【解决方案1】:

    显然,Chrome 在被进程终止关闭时并不高兴。它具有检测这种确切情况的机制。
    它有一堆正在运行的进程,我认为这可能是一种优雅地关闭它的方式(我可能错了,但我记得一旦我设法做到了),通过仔细选择进程的顺序被杀死(crashpad-handler、utility、renderers,在 master 之前),但现在我可以'不这样做,我也不知道这实际上是多么优雅。

    注意:我个人认为这种行为非常有用,因为我打开了很多 Chrome 窗口,每个窗口都有很多标签,每次我需要重新启动笔记本电脑时,我从任务管理器中关闭Chrome,这样下次我打开它就会恢复当前状态。

    回到我们的问题,一种方法是获取它的窗口并将[MS.Docs]: WM_CLOSE message 发送给它(也检查[MS.Docs]: Closing the Window)。请注意,它是 Win 特定的!

    • 您已经拥有获取具有特定名称的进程 (pids) 的代码
    • [SO]: Get the title of a window of another program using the process name (@CristiFati's answer) 包含从进程(ids)获取窗口(标题)的代码。实际上它包含更多,但这就是您需要的(enumWindowsProc 和 enumProcWnds 函数)
    • 关闭窗口的代码:

      win32api.SendMessage(0x005C0974, win32con.WM_CLOSE)  # 0x005C0974 was Chrome's (main) window handle in my test
      
    • 您需要做的就是将以上 3 项结合起来(稍作改动)

    另一个适用于 Windows 的示例:[SO]: Keyboard event not sent to window with pywin32 (@CristiFati's answer)。

    【讨论】:

    • 去看看我能不能完成这项工作,并会相应地更新。我想知道 FireFox 是否显示类似的行为?
    • 不显示错误信息。如果它被异常关闭(从任务管理器),再次启动时它将重新打开所有选项卡。如果正常关闭,再次启动时,只显示主页(可以从设置中更改)。
    • 这行得通。我不喜欢依赖 win32 api,尽管这可能是必要的。将继续寻找使用 psutil 的替代方法,如果我找到工作方法,将进行更新。感谢@CristiFati 的帮助!
    • 您也希望能够在 Nix 上运行吗?我不知道当进程被杀死时这两个浏览器的行为如何。另外我不知道如何使用他们的 Windows 系统(我想这取决于 X 服务器 API)。
    • 是的,现在该程序与平台无关。我最初使用的是上面提到的 win32,但看到了这些性能问题,我们未来的目标之一是将这些终端从 Windows 中移开。目前,此解决方案将修复它,但我们可能有其他选择来缓解此问题。 Psutil 与平台无关,所以如果我能弄清楚如何利用该库做类似的事情,它至少应该更容易在 Linux 上工作。
    【解决方案2】:

    一个更通用的版本,将关闭消息发送到应用程序,包括那些仅在系统托盘中可见的应用程序,并包含所有需要的导入:

    import win32con
    import win32api
    import win32gui
    import win32process
    import psutil
    
    def enumWindowsProc(hwnd, lParam):
        if (lParam is None) or ((lParam is not None) and win32process.GetWindowThreadProcessId(hwnd)[1] == lParam):
            text = win32gui.GetWindowText(hwnd)
            if text:
                win32api.SendMessage(hwnd, win32con.WM_CLOSE)
    
    def stop_app(app_exe):
        for process in psutil.process_iter():
            if process.name() == app_exe:
                win32gui.EnumWindows(enumWindowsProc, process.pid)
    
    stop_app("appname.exe")
    

    (基于问题中的“根据 CristiFati 推荐的快速解决方案”,但将“pid”更改为“lParam”,包括所需的导入,并且也适用于仅在系统托盘中可见的应用程序。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-28
      • 1970-01-01
      • 2014-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多