Изящно убить Chrome для Windows с помощью Python - PullRequest
0 голосов
/ 25 февраля 2019

Я пытался определить способ закрытия Chrome (и других процессов) изящно, используя Python.Я прошел через несколько методов, но все они приводят к тому, что 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)

Ответы [ 2 ]

0 голосов
/ 26 мая 2019

Более общая версия, которая отправляет сообщения о закрытии приложениям, включая те, которые видны только в системном трее, со всеми необходимыми включенными импортами:

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', включает в себя необходимый импорт, а также работает с приложениями, видимыми только в системном трее.)

0 голосов
/ 27 февраля 2019

Видимо, Chrome не устраивает закрытие по завершении процесса.У него есть механизм обнаружения этого точного сценария.
В нем запущено множество процессов, и я думаю, что это может быть способ изящно закрыть его (я могу ошибаться, но я помню, что однажды мне удалось это сделать), тщательно выбирая порядок, в котором находятся процессыубит ( обработчик сбоев , утилита , рендер s, до master one), но теперь я не могу этого сделать,я также не знаю, насколько это изящно.

Примечание : лично я считаю это поведение очень полезным, потому что у меня есть много открытых Chrome окон, в каждом из которых есть много вкладок,и каждый раз, когда мне нужно перезагрузить ноутбук, я закрываю Chrome из Диспетчер задач , чтобы при следующем открытии он восстанавливал текущее состояние.

Назаддля нашей проблемы одним из способов было бы получить его окно и отправить ему сообщение [MS.Docs]: WM_CLOSE (также проверьте [MS.Docs]: закрытие окна ),Обратите внимание, что Win определено!

  • У вас уже есть код, который получает процессы ( pid s) с определенным именем
  • [SO]: Получить заголовок окна другой программы, используя имя процесса (ответ @ CristiFati) содержит код, который получает окна (заголовки) от процессов ( id s).На самом деле он содержит больше, но это то, что вам нужно оттуда ( enumWindowsProc и enumProcWnds функции)
  • Код, закрывающий окно:

    win32api.SendMessage(0x005C0974, win32con.WM_CLOSE)  # 0x005C0974 was Chrome's (main) window handle in my test
    
  • Все, что вам нужно сделать, это объединить вышеуказанные 3 (с небольшими изменениями)

Еще один пример, который работает с окнами: [SO]: событие клавиатуры не отправленов окно с pywin32 (ответ @ CristiFati) .

...