使用Python优雅地杀死Windows版Chrome

时间:2019-02-25 20:04:20

标签: python browser wmi pywin32 psutil

我一直在尝试确定一种使用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()代替各种信号类型的terate()(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)

2 个答案:

答案 0 :(得分:2)

显然, Chrome 在由于进程终止而关闭时不满意。它具有检测这种确切情况的机制。
它正在运行许多流程,我认为这可以是一种通过仔细选择流程顺序来正常关闭流程的方法(我可能是错的,但是我记得一旦我做到了)被杀死( crashpad-handler utility renderer ,在 master 之前),但是现在我可以不这样做,我也不知道那实际上是多么优雅。

注意:我个人认为此行为非常有用,因为我打开了许多带有许多标签的 Chrome 窗口,并且每次我需要重新启动笔记本电脑时,从任务管理器关闭 Chrome ,以便下次打开它时,它将恢复当前状态。

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

  • 您已经具有使用特定名称获取进程( pid s)的代码
  • [SO]: Get the title of a window of another program using the process name (@CristiFati's answer)包含从进程( id s)获取窗口(标题)的代码。实际上它包含更多内容,但这就是您所需要的( 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)

答案 1 :(得分:1)

一种更通用的版本,用于向应用发送关闭消息,包括仅在系统任务栏中可见的关闭消息,以及所有必需的导入项:

app:popUpTo

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